Yield function not working on signal defined in self

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

Hey all,

I have created a class “Singleplayer_Game” that’s used to communicate between the current game and save files.

In this class, I have defined a function save_game() that is used for saving specific information. Within this function, I call another function get_save_info() that retrieves information from a child node of “Singleplayer_Game”. In order to give get_save_info() the time it needs to collect the information and store it in a dictionary in “Singleplayer_Game”, I initially assumed I’d use a yield(timer) implementation, but I found that to be a hassle as I don’t exactly know how long it will take to collect that information. Since my project is in it’s very early stages, I will add tons of information that the game might need to save, which makes it take longer.

According to this code-example of the reply from Diean Jeans, it’d be possible to emit a signal at the end of a function, to let listeners know that function has finished executing. When I try this with a parent and a child node, it works splendid, like this:
Parent: emit_signal("example")
Child: yield(get_parent(), "example")

However, when I try to do this within the same class, like this;
emit_signal("example") and yield(self, "example")
it doesn’t work, and never gets past the yield line.

Is there something I’m missing?

Thanks in advance!

~FortunePilot

:bust_in_silhouette: Reply From: njamster

So your tree looks like this?

- Singleplayer_Game
    - Child

Then (from what you describe) your code should look like this:

SinglePlayer_Game.gd:

func _ready():
	save_game()

func save_game():
	print("Calling child's get_save_info function'")
	$Child.get_save_info()
	yield($Child, "child_done")
	print("Child is done, parent continues")

Child.gd:

signal child_done

func get_save_info():
	yield(get_tree().create_timer(1.0), "timeout")
	emit_signal("child_done")

But later on you state this:

However, when I try to do this within the same class, like this; emit_signal("example") and yield(self, "example") it doesn’t work, and never gets past the yield line.

This leads me to believe what you’re trying instead is something like:

func save_game():
	print("Calling child's get_save_info function'")
	$Child.get_save_info()
	emit_signal("example")
	yield(self, "example")
	print("Child is done, parent continues")

Which of course doesn’t work! You’re first emitting the signal and then pause the execution of your function until that signal is emitted again (i.e. never).

First off, sorry that I haven’t included any code-examples, which makes it harder to understand what my code looks like, so I’ll include it here to make it easier to understand. Of course I shrunk code down to this, but the idea and working should stay the same:

Singleplayer_Game.gd:

signal example
var save_information

func get_save_info():
    print("Collecting save info from child node.")
    save_information = $Child.save_information
    emit_signal("example")

func save_game():
    print("Calling get_save_info")
    get_save_info()
    yield(self, "example")
    print("Saving game...")

func _ready():
    save_game()

Execution doesn’t get past the yield() in save_game().

FortunePilot | 2020-03-29 19:04

If you replace the call to get_save_info() with call_deferred("get_save_info") it should work. Sadly, I’m not able to explain why this works - but apparently it does!

njamster | 2020-03-29 21:20

Thanks a lot! :slight_smile:

FortunePilot | 2020-03-29 23:47

your code do this:

save_game() # call save_game() function

in save_game function:
1) print text
2) call function get_save_info()
3) all code in function get_save_info is executed
4) here you try yield for signal "example", but this signal is already emitted because the function that call it is already execute and finished.
5) code under yield never run

using call_deferred(“get_save_info”) as njamster say, you get this:

save_game() # call save_game() function

in save_game function:
1) print text
2) call deferred function get_save_info() (this function is executed in next process tick)
3) Here you try yield for signal "example". Code pause here. In next process, the function get_save_info() is executed and that function emit signal "example", then the function save_game() is resumed
4) execute rest of code of this function

newold | 2020-03-31 22:43

Makes sense! Thank you for explaining. :slight_smile:

njamster | 2020-04-01 09:40