Patom
Patom

Reputation: 11

Is there a way to await for an if statement to be true?

I am trying to make a multiplayer godot game, and I want to make sure every @rpc have been read by all peers before continuing to read through the main part of the code.

So I made a variable that increases every time one of the rpc is read.

The problem is that I want to make sure that the main program is stopped while this variable is below the number of players.

I have been searching a lot for documentations, but I only came across await which uses signals (so no links to variables), while (which just completely freezes the program) and have been trying to find functions that launches anytime an if statement is true (without luck).

Upvotes: 1

Views: 1748

Answers (1)

Theraot
Theraot

Reputation: 40325

No, there isn't. You need to build this.

As you found out await works with signals. Well, you can create your own custom signals. So in the code where you increment the variable, you can either add a check, or emit a signal, or both.


For example, one way would be to define a setter for your variable, and have signal when it changes to the value you want. Then you connect or await it.

signal expected_x_reached()

var expected_x:int

var x:int:
    set(mod_value):
        if x == mod_value:
            return

        x = mod_value
        if mod_value == expected_x:
            expected_x_reached.emit()

Addendum: In this scenario, you might want to have a setter for expected_x too (since x == expected_x can become true because x changed or because expected_x changed). But I'll keep it as is for clarity.


Be aware that you can define a signal for when a value changes, and connect an anonymous method to check fo the value (which is useful if different parts of your code need to wait for different values):

signal x_changed(value:int)

var x:int:
    set(mod_value):
        if x == mod_value:
            return

        x = mod_value
        x_changed.emit(mod_value)

In this case the method connected will get the value:

obj.x_changed.connect(
    func (value:int) -> void:
        if value == expected_x:
            # do something, emit a signal, whatever
            pass
)

If is not code you control... You might have to find an adequete existing signal. Or you need to check for it in _notification or some other callback.

Worse case scenario you need to check every frame (because there is no notification mechanism, and you can't add one without a custom build of Godot).

You can check every frame using _process or connecting to the process_frame signal of the scene tree.

Using _process could be like this:

func _process(_delta:float) -> void:
    if obj.x == expected_x:
        # do something, emit a signal, whatever
        pass

You might do this in your existing nodes, or create a new node to keep track of the variable and emit the signal... Which other nodes can connect to.


If you were writing a loop to wait, you should be able to either:

  • Convert it to code that runs in _process (doing one iteration each frame).
  • Use await※ on process_frame, or on some custom signal.
  • Or break it with call_deferred. I'll advice to not abuse this, there is a limit to how many deferred calls you can have going.

※: I'll also point out that there is a drawback to awaiting: it cannot be cancelled, and a freed object cannot resume from an await (which can result in some nasty bugs). If you run into such problems, consider refactoring from await to continuations connecting to the signal using CONNECT_ONE_SHOT or having code to disconnect when it is appropiate. The reason being that when objects are freed, they automatically disconnect.

Upvotes: 1

Related Questions