I have what seems like an extremely simple event system comprised of different custom resources all inheriting from the same type. There is a top-level “Event” resource that runs any number of “EventItem” resources in sequential order. The “Event” resource runs a for-loop that awaits an “event_item_finished” from each “EventItem” derived resource. Most work perfectly fine but some get completely stuck with the “Event” for-loop awaiting for the finished signal from only certain “EventItem” scripts. They are very simple scripts and I can’t for the life of me figure out why as there are no errors thrown and the debugging stack trace follows the correct order.
event.gd
class_name Event
extends Resource
signal events_finished
@export var events: Array[EventItem]
func run_event(_gm: GameManager) → Signal:
for event_item in events:
await event_item.run(_gm)
return events_finished
class_name EventItemCurrency
extends EventItem
@export var amount: int
func run(_gm: GameManager) → Signal:
File.progress.inventory.change_currency(amount)
return event_item_finished
The currency one causes the “Event” for-loop to get stuck awaiting “event_item_finished” forever. The File.progress.inventory is a very simple autoloaded inventory resource:
inventory.gd
class_name Inventory
extends Resource
signal currency_changed
@export var currency: int
func change_currency(amount: int) → void:
currency += amount
currency = clampi(currency, 0, 99999)
currency_changed.emit()
The signal is returned from each EventItem’s run(). The odd thing is most of the other EventItem derived scripts work just fine and are more complex. For example, I have a dialog one that requests dialog from the top level game manager. The only difference is there is an additional await from another object:
Yes, await waits for the signal to be emitted. Returning the signal object doesn’t emit the signal, and function that does so it not a coroutine. For example, the following will never print “done”
signal s
func _ready():
print("start")
await foo()
print("done")
func foo():
return s
Ok, I switched all EventItem scripts to emit the signal instead and they all work as intended. What is the use case for returning a Signal from a function then? I’ve read the docs section on await about 10 times and I guess the examples were a bit too succinct for me to understand the concept.
In some cases I do need to wait until the previous event finishes, such as a character animation or waiting for the player to advance dialog. Some events can run immediately while others need to wait. The idea was create a simple but flexible system that could accommodate any number of design decisions.
So basically I was overusing await and signals where they weren’t really needed. I think I understand enough to get things working as intended, thanks!