+1 vote

TL;DR

  • I'm trying to await a method I call via "Object.Call(name...)" in C#.
  • But I cannot get an Awaitable
  • How would I know if an async method I called is finished?

Background

I'm writing an events sequencer and I'd need to call methods, and ideally also set properties, much like AnimationPlayer does.

I need ot wait for the method to finish. The method could be async, so I was trying something like:

    object result = target.Call("RunStepText", "TestParameter");
    await Task.FromResult(result);

And also:

    await target.Call("RunStepText", "TestParameter");

And

    object result = target.Call("RunStepText", "TestParameter");
    await ToSignal(result, "completed");

But in C#, Object.Call returns a Variant and I do not really know how to deal with it.

I have read about the completed signal for method calls. Is this emitted for every function call? In any case, I haven't been able to receive it either.

How can I call a method on an arbitrary object and check if the call is finished or if there are coroutines holding on to the call?

I'll resort to use dedicated signals if needed but that would force me to write dedicated code for every object I want to automate via my sequencer.

in Engine by (39 points)
edited by

1 Answer

0 votes

I'm trying to figure this out today as well. Engine call awaiter support in the vein of ToSignal could be neat, e.g. await ToComplete(...);

But do you need to use Call? You might be able to use C# async/await features more directly. I found two ways to do something similar to GDScript's yield until coroutine "completed". At least, these techniques work with my own C# functions...

1) Use Task.StartNew or Task.Run to wrap a call and await that task. Note, this technique will execute the action on a separate thread which may cause some strange interactions with the engine if you call into it. This might be a good option if you have some heavy lifting to do outside of the game world, for example if you need to call web services or compute the ten billionth prime number.

2) Use a regular C# async method and await a direct C# call to it. This will execute on the same thread and is usually what I want when breaking down game logic into composable asynchronous functions (coroutines). Basically, you let C# build the state machine and continuation flow for you...

async Task<bool> ConfirmPlayerLikesChocolate() {
    // Tween in the question label...
    await TweenLabel("Do you like chocolate?");
    // Pop the "Yes!" button.
    await FadeInButton(0.1f, "Yes!");
    // Wait 5 seconds to fade in the "No." button...
    await FadeInButton(5.0f, "No.");
    // Wait for player to select...
    // Ignore buttons because nobody dislikes chocolate.
    return true;
}

async Task AnnoyPlayer() {
    bool likesChocolate = await ConfirmPlayerLikesChocolate();
    if (!likesChocolate) {
        // CRASH!
    } else {
        // Oh yeah? What's your favorite kind of chocolate?!
    }
}

Note this brings the usual benefits of C#: composability, name checking, type safety, etc. Assigning the await expression to int instead of bool produces compile-time error.

You can write async void functions but can't await them. Just change the return type to Task. Or, if you need to produce a result, Task<TResult> and return something of that type as usual.

by (78 points)

Thank you. Hoever I needed to use Call, as my call sequences come from a data file, not code. The root cause of this is that Awaitables are not serializable into Variants, this will be fixed in an upcoming version according to the devs.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.