Coroutines in AGS

Started by Crimson Wizard, Mon 03/02/2025 13:52:02

Previous topic - Next topic

Crimson Wizard

I have recently rewrote a engine's script executor in the AGS 4 branch (see PR #2621). While the script format and basic execution remains exactly same, this rewrite changes the way the script execution state is handled. Among other things, it introduced an improved concept of "script thread". AGS had a sort of a "script thread" idea before, there has been 2 threads: normal one which run most script, and non-blocking one which run "repeatedly_execute_always". But this system was very limited, and not convenient to expand. The new system allows to do 2 following things relatively easily:

1. Create new (temporary) "script threads" dynamically. The "script thread" contains its own stack memory (for local variables) and callstack queue (for remembering nested function calls).
2. Saving script thread's state and restoring later. This means that the whole local state of a script's execution is saved at a current point, kept recorded for an undefined duration, and then later may be run from the same point again.

In my opinion this opens a potential for implementing coroutines in AGS. Coroutines are types of functions that can pause, then wait for something (either some event, or a external command) and resume.
I have spoken about my vision of what coroutine may be in AGS earlier here:
https://www.adventuregamestudio.co.uk/forums/editor-development/feature-request-behavior-of-hotspot-that-results-in-a-room-change/msg636665195/#msg636665195
But that was never meant to be a final plan, and when I think about this now I have doubts about few things.
Then I made a dirty experiment here:
https://www.adventuregamestudio.co.uk/forums/editor-development/feature-request-behavior-of-hotspot-that-results-in-a-room-change/msg636668451/#msg636668451
Again, this was merely a technical proof of concept, not a feature suggestion.

I'd like to open a proper conversation about how coroutines may be designed in AGS, both from the point of view of script syntax and internal implementation.

For the reference, following is technically possible to do with "script threads" now:
- script threads may be created anytime, and stored by the engine; they may be identified by something (whether string name or numeric index);
- script threads may be paused at any or almost any instruction in script, and resumed by the engine (resuming means simply that engine runs previously recorded script thread again);
- running a saved script thread may be done either by engine's updating the game (i.e. if there's a list of script threads which are checked on each game update), or by a direct command from a script.
- script threads may be cloned (copied and saved as a different thread object); idk if that is necessary, but it's possible.
- saving or cloning a script thread may be full or partial. For instance, we may record/copy only the latest nested function call and its local data, but ignore everything that preceded it.

What cannot be done:
- as far as I can tell, we cannot save script execution that have nested engine calls in them. What I mean is, suppose there's a engine function that can be run from the script, but also calls another script. Then you have an interleaved nested script and engine calls: engine -> script -> engine -> script -> ...
This kind of nested call was not possible before, it is possible now with the new executor system, but we won't be able to save such callstack nor restore it, because engine own functions cannot be restored by the script executor. I suppose there may be ways around it, but this seems too complicated, so perhaps not worth trying.
Then, perhaps the engine should not make such nested calls on the same script thread, but always create new temporary script thread whenever it has to run another script callback while being inside one script callback already (like what happens when it runs rep-exec-always, while being inside a Wait called by a script).

Above should be kept in mind when designing coroutines feature.



SMF spam blocked by CleanTalk