Resumed function after yield, but script is gone.

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By MOSN

My script that has worked fine for a long time suddenly started frequently giving me this error:

resume: Resumed function 'start_round()' after yield, but script is gone. At script: res://Scripts/BattleScript.gd:70

And directly afterwards this:

_disconnect: Disconnecting nonexistent signal 'turn_end', slot: 6723:_signal_callback.

The is defined on the node and has worked fine until now, I can also see in “remote” that the node holding the script is not freed, and that the script variables can still be seen on it in the inspector which to me says that the script is still there and not “gone”. I can’t seem to find any pattern to when it happens, sometimes it runs through those same functions with no problems.

So… What the hell is this error and why is it happening? For the record it doesn’t seem to crash the game entirely and it only shows up in the “Errors” tab.

:bust_in_silhouette: Reply From: Inces

This happens only when sript currently yielded is freed by other instance or within other function. If You can find this node in remote, that means there must be another instance of it, maybe created dynamically, that becomes freed. Find all who calls to ever free this node in print something before this call, so You will know how many times does this happen, how many additional nodes do You get.

Anyway, this error is hard to get rid off. General sollution is to design freeing nodes by themselves, after they resume yielded function. But sometimes it is not comfortable. Paste your code, we can see to it

The problem with that is that this node neither gets dynamically created or freed anywhere in my code, it’s my battle scene and it’s supposed to just be there permanentely, so the one I can see in remote must be the right one.
I randomly stumbled upon a problem that seems to have been partially responsible for the issue, even though it doesn’t really seem to match the error: Basically my script called a function then immidiately afterwards called a yield that waited for the end of that function (since it has some timers involved), but I had screwed up an if statement so sometimes the function would end immidately before the yield triggered and the script would wait for a signal that had already happened (and wouldn’t happen again). I don’t understand why that caused this error though and I can’t replicate it in a different project, but it seems that after I fixed this the error is almost gone. It has happened just once after I fixed it, but with a different signal and function on the same node… And that function doesn’t seem to have the same issue.

MOSN | 2022-04-21 10:14

What You said may be true reason of error, but only if error shows up at the moment of quitting project.

Inces | 2022-04-21 15:23

I get what you’re saying, but it doesn’t though… It happens while the game runs and it doesn’t crash it either.

MOSN | 2022-04-21 15:48

This kind of errors never crash project.
the signal error suggests, that disconnection has been called twice. So it is very likely, that resume() is called twice and maybe provokes former error. Can You show the code where it happens ? Disconnection, yield and resume ? Aren’t You calling some of these in process() ?

Inces | 2022-04-21 19:17

No nothing related to that is called in process(). This is the bit of code that seems to have caused it after I fixed the error relating to the signal I first posted:

xp_gain(0, total_xp_gain)
yield(self, "xp_done")

The xp_done signal is emitted at the end of the xp_gain fucntion which looks like this:

func xp_gain(actor, amount):
var level_up = false
party_control[actor].get_node("XPBar").max_value = 5*party_characters[actor].level
party_control[actor].get_node("XPBar").value = party_characters[actor].xp
var remaining_amount = amount
for i in range(5):
	party_control[actor].get_node("XPBar").update_value(party_characters[actor].xp + remaining_amount)
	remaining_amount = remaining_amount - (party_control[actor].get_node("XPBar").max_value - party_control[actor].get_node("XPBar").value)
	yield(self, "next")
	if party_control[actor].get_node("XPBar").value == party_control[actor].get_node("XPBar").max_value:
		level_up = true
		party_characters[actor].level += 1
		party_characters[actor].xp = 0
		text_box.text = "%s has gained a level!" % party_characters[actor].character_name
		text_box.scroll_start()
		yield(self, "next")
		party_control[actor].get_node("XPBar").max_value = 5*party_characters[actor].level
		party_control[actor].get_node("XPBar").value = 0
	yield(get_tree().create_timer(0.5), "timeout")
	if remaining_amount <= 0:
		party_characters[actor].xp = party_control[actor].get_node("XPBar").value
		call_deferred("emit_signal", "xp_done")
		break

I’ve cut out some of the decidedly irrelevant parts here so yea it’s a pretty long function. The “next” signal is emitted both when a progress bar (in this case XP) is done filling up and when text is finished being written (I use scrolling text).
To clarify the error that I got in this case was that it resumed end_battle() (the function which the first code bit is from) after yield and stated once again that the script was gone. I know this is kind of a mess, but I can’t seem to replicate the error again, so that makes it hard to get more specific.

MOSN | 2022-04-21 19:58

Alright it happened again, same function but a different yield().

enter image description here

MOSN | 2022-04-22 09:41

What about disconnecting signal ? You do this somewhere in code, don’t You ?
Is battle sript ever queing free throughout whole project ? Are there situations with more than 1 instance of battlescene ?

Inces | 2022-04-22 13:32

No I don’t use disconnect() or even connect() for the battle scene. The signals are called directly in the code using emit_signal().
And it’s a no to both your other questions, there’s just one and it is never freed.

MOSN | 2022-04-22 13:50

Ok, I think these are some buggy errors, especially disconnection one. This happens sometimes, MeshLibrary also provokes this type of bugged console reports

Inces | 2022-04-22 14:08

Fair enough, it did seem like a very strange error to get here. Unfortunately that doesn’t make it much easier to find the actual issue…

MOSN | 2022-04-23 07:04

:bust_in_silhouette: Reply From: jeffreydvp

I was running into this exact same issue for an entire day, after changing a bunch of seamlessly non-offensive editor settings.

This was the line of code generating the error: “Resumed function after yield, but script is gone.”

yield(get_tree().create_timer(0.2), 'timeout')

Discovered that this happens when you have this editor setting set to true:

interface/editor/save_on_focus_loss = true

Change it to false.

You can get to editor settings from the Editor menu option at the top of Godot.