Coroutine Limitations:
Coroutines functions have the following limitations in order to function correctly:
No outside dynamic state can be used: Coroutine cannot use or depend on any dynamically changing state outside of the coroutine (no closured variables), except variables passed through the arguments of the coroutine function.
Deterministic execution flow: When running with the same arguments, the coroutine should always result in the exact same sequence of the yield commands. No outside state should ever change the order or flow of the yield actions within the coroutine.
Serializable arguments: Coroutine arguments must be serializable to JSON, in order to be saved / loaded correctly, so they need to be of simple types.
yield side effects only: Any action, that causes side-effect, should be called as yield <coroutineCommand>(...).
Supports infinite loops: Once entered infinite loop, there should be no way to exit it, except terminating the coroutine. If your loop has break statement, it's not a truly infinite loop.
yield doReduce() as a first command in its scope. It will make sure the coroutine saved position doesn't grow infinitely.yield doReduce(1), yield doReduce("mainLoop"), and so on.
Type definition for a coroutine generator function (used to run Move scripts of the objects).
Coroutines are modern replacement for the LBA move scripts. They are designed to control the sequence of object actions.
Every coroutine runs its commands one by one until finished or stopped.
The coroutines run as asynchronous, multiple step functions, and can be paused and resumed. Also the coroutines persist their execution state and restore automatically during save/load.