Await a signal with a timeout in Godot 4.x

If you or a loved one has ever struggled with trying to await a signal or a timeout, worry no more!
Here’s a solution:

func with_timeout(sig, timeout):
    var dummy_obj = Object.new()
    dummy_obj.add_user_signal("result")
    var sig_first = func(): dummy_obj.emit_signal("result", [false])
    var timeout_first = func(...sig_result): dummy_obj.emit_signal("result", [true, sig_result])
    get_tree().create_timer(timeout).timeout.connect(timeout_first)
    sig.connect(sig_first)
    var dummy_signal = Signal(dummy_obj, "result")
    var result = await dummy_signal
    return result

What this does is create a temporary, locally scoped signal, and outputs true or false depending on which signal calls the local signal first (and possibly returns the result of that signal, if it’s not the timeout).
I couldn’t find anything like this anywhere else, so I thought I’d post this here in case Godot never implements something like this.

Not sure exactly what this does. How is this different from using

await get_tree().create_timer(1.0).timeout

1 Like

I think they are different.
The function with_timeout could return two result:
= true when timeout go first.
= false when the signal go first.

So, it can be used to detect whether a signal emit within a specific time period.
For example, you can use it to check a Button is pressed in 2.0 second or not.

But, I am not sure will the var ‘dummy_obj’ cause memory problem since it didn’t ‘free()’ after using.
Maybe use RefCounted or Resource instead?

You’re right, it doesn’t free. You can use a RefCounted, and even free it just to be safe, just after

        var dummy_obj = RefCounted.new()
	var result = await dummy_signal
	dummy_obj.free()
	return result