Advertisement

Suspending a script and returning a value

Started by June 23, 2023 09:42 PM
5 comments, last by ic0de 1 year, 5 months ago

So I wanna do I thing in a script which is kinda like a co-routine but I'm not sure what to call it, while looking at the example it wasn't obvious how I would achieve it.

I wanna have a script call a C++ function like so:

auto result = get_dialogue_choice();

Then on the C++ side the script would be suspended, the player would choose their option after some amount of time and the script would then be resumed as if that function had returned a value. It all seems very clear how to suspend the script and then resume it, I'm just not sure how I would get the result back to the script (ideally as though it behaved like a regular function call from the scripts perspective). Anyone know if I can do this?

The question is quite abstract, but I'll try to answer.

The concept you might need is called “Promise” (or “Future”). The idea is that instead of returning chosen value, get_dialogue_choice immediately returns an object, namely “promise object”. Think of it as a box with a value (instead of the value).

The trick is that the box is empty when the function is returned - the player haven't chosen the value yet. The value actually appears when the choice is made.

How the value is delivered there; how the script is notified about that and how it actually behaves - is up to the implementation. Usually, promise objects can be queried for the existence of the value (.is_ready() - “box is ready, and has a value inside?” ); and queried for the value itself (.get() – “unpack the box”).

Now you can see how a promise-compatible “if (x == “constant”) { return A; } else { return B; }” function would look like and how. It would accept a boxed object (x); return a boxed object (containing either A or B), but which one exactly is not decided upon return. Once x is resolved; then this box can be resolved as well, becoming A or B (and propagating resolution chain further).

This pattern lets your code execute immediately (storing a chain of “what to do next” list) and actually perform the code later.

Implementing it is a nice exercise, but I suggest you not to try to apply all above “as is” in C++. I would advice you using an existing scripting system that supports what you want (if still want to be fancy: wrangle JS engine, for example V8, to do that: promises are common in JS, for example your trusty fetch returns one)

None

Advertisement

Yes, @rampeer is right, promise object is the one that suits this problem quite well without knowing much context.

If your problem requires you not to wait for user response in your script, meaning non-blocking fashion i would suggest you to try my implementation of Promise<T> object.

It then can be implemented using event loop if you prefer singlethreaded Node.js-like script execution which is secure in terms of race conditions, or you could do it multithreaded: both are supported.

Consider taking a look at examples directory.

If you really don't want your script code to have any await statements and still being non-blocking then you may look into fiber-based stackful coroutines or C++20 stackless coroutines but that's a real mess in terms of implementation madness.

rampeer said:

Implementing it is a nice exercise, but I suggest you not to try to apply all above “as is” in C++. I would advice you using an existing scripting system that supports what you want (if still want to be fancy: wrangle JS engine, for example V8, to do that: promises are common in JS, for example your trusty fetch returns one)

Please take note that this question was posted in the AngelCode-forum, meaning OP is already using a scripting-system (AngelScript) and the question applies on how to interface coroutines with that.

I recommend looking into aspromise that romanpunia implemented.

But if you don't want to use that, a simple implementation can be done like this:

// In AngelScript:
int get_dialogue_choice()
{
	suspend();
	return retrieve_dialogue_choice();
}

The get_dialogue_choice script function can be implemented by default by your application so the script writer doesn't have to know it is a script function it is calling.

The functions suspend and retrieve_dialogue_choice would be implemented in your application and registered with the script engine.

suspend simply calls asGetActiveContext()->Suspend() after which the script execution would be suspended and the asIScriptContext::Execute returns. Your application then continues the control loop and once the user makes a choice in the dialogue the choice is written to a variable, which can get read and returned by the retrieve_dialog_choice function (alternatively you can just register the variable with the engine directly).

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Ok so I ended doing something a bit more low tech, I just made a dialogue_box class and stored the result inside of it. Then I wrapped the suspend and get result inside of a function on the AngelScript side like @witchlord described. Thanks guys!

This topic is closed to new replies.

Advertisement