await issues in gdscript?

Godot Version

Godot 4.5.1

Question

Our gdscript-based game makes heavy use of await to display dialogs for the user: the code calls a function which displays the dialog, then awaits a done signal from the dialog, which is emitted when the user clicks on a button.

That works fine, generally speaking. But very occasionally, for no apparent reason, the await doesn’t quite work as it should: the code continues immediately, and then, when the user clicks on the button, the code following the await is executed again.

Has anybody else had similar issues with await? Before anybody asks, none of this is done in _process() methods, it is all input-driven.

You’d need to share your code that handles it, otherwise it’s hard to tell.
I’ve never encountered a problem before with awaits that wasn’t just my mistake.

3 Likes
  1. Does it happen with the same dialogs every time.
  2. If not, what other common places do you see it happen? (For example in the first dialog in a scene, only in the middle, the last message, etc.)
  3. Are your done signals specific to each dialog, or are you using the same signal every time?
  4. Do you have a snippet of code you can share that always causes this problem to happen? Or failing that sometimes causes this problem to happen?
1 Like

No, unfortunately it is not always the same dialogs, and the bug is not easily reproducible. As I say, it almost always works as it should. And each dialog has its own done signal.

Eliminate all awaits.

That’s helpful information.

So this tells us that it is likely a race condition.

That eliminates the possibility that a firing done signal from a previous dialog is triggering the next one.


We are going to need some code to work from to give you help with this. An example of something that caused this once, or you’re pretty sure caused this once would help, but barring that an example of the code in general would help.

While _process() is one way a race condition could happen, there are plenty of other places it could happen.

The fact that the code is executed twice is very interesting. And odd. It indicates that the signal is being sent twice.

Ignore @normalized. They don’t like await. From a design point of view, I agree it’s good to avoid await when you can, but there’s nothing inherently wrong with what you’re doing. Though that solution would fix your problem.

4 Likes

Code would be very helpful here. I am especially curious about the input event you are using to send the signal.

1 Like

You may be violating some community guidelines here. If you want us to take an await usage pissing contest - I’m all for it.

Getting rid of awaits in situation like this is the best course of action. If nothing else it’s a good debugging strategy as it’ll make your program execution flow much easier to follow, and you may spot where you went wrong with your logic. Once you get it working properly with regular signal handlers, then you can re-introduce awaits if you need that extra edge of elegance.

2 Likes

I hoped you’d take it as me giving you a hard time for your bluntness, not actual disagreement. Which is why I told OP that you were correct. I don’t disagree with anything you’ve said. It just might be a big ask.

3 Likes

You could try using an animation player - instead of ‘await’ you could run an animation to finish the dialog. You could use a method call keyframe to set a flag at the start and end of the animation.

This might be a bit more stable than threading, just not working on multiple cpu cores - you can probably run animations in threads too …

For early exit functions you could simply also reset the flag

Then I hope you wouldn’t mind if I start returning the favor on account of your llm grade verbosity and fisking tendencies.

Anyway @glevner you’ll have to try to make a minimal reproduction project or at least provide some code and relevant scene setup. There’s 99% chance that the bug is in your code and not in Godot’s coroutine handling.

As far as awaits go, I don’t think they are bad from a design perspective, but rather from an experience perspective. Don’t use them if you can’t fully control them. If you don’t know whether you can or can’t control them - then you probably can’t control them and therefore shouldn’t be using them outside of experimenting and learning.

4 Likes

Thanks for all your helpful input! Conclusion: it is probably a bug in my code somewhere, not in Godot’s await command. So I will look harder in that direction.

1 Like

I am waiting for the user to click a button, so an animation won’t help me.

It’s just a connection from a button’s pressed signal.

Sorry i misread your original post, i see the dialog closes and you await for the signal - have you considered just showing a box of controls for the dialog and spamming codes like:

if dialog_node.visible:
    return

at the start of all the other functions? The signal hides the dialog:

func _on_dialog_button_press():
    dialog_node.visible = false
    dialog_node.activated = false # for example

The await is halting execution for the dialog, sometimes its safer to let it run and use conditionals, in some case the logic doesnt seem to work at all, depending on what events are running and what function is resetting the logic (i.e. physics_process can apparently run multiple times per frame).

I think you may be well served by using a flag to ensure that only one signal at a time is listened for.

Something like:

if flag: return 
flag = true
await signal
run_signal_handler()
flag = false
1 Like

You do you. I learned a new word. Never heard “fisking” before. Definitely fits me. Also I predate LLMs so their verbosity is clearly copying me. Also, I’m not as nice as LLMs. :slight_smile:

2 Likes