[Ohrrpgce] Script fibres/multitasking (again)

Ralph Versteegen teeemcee at gmail.com
Mon Sep 5 06:55:06 PDT 2016


On 5 September 2016 at 04:21, James Paige <Bob at hamsterrepublic.com> wrote:

> I read this all, but I am going to have to read it all again later when I
> don't have anyone shouting and poking me with lego giraffes ;)
>

Onto lego already! It's only recently that I appreciate "they grow up so
fast". (I was imagining you getting battered with a stuffed toy giraffe
until I reread)


> I think before I will be able to provide helpful feedback, I will need to
> internalize all this enough that I can understand now the implementation
> can be broken into the smallest possible discreet steps. (A must be done
> before we can do B, B must be done before we can do C and D, etc.)
>

The reason that I brought up ordering of fibres immediately is that my
first step was to remove the script queue stuff, which was never used for
anything aside from script logging. It had been my intention to use it to
allow prioritising some types of triggers over others. But it's actually
not the first thing that needs to be decided.

Various of the script commands that would be added can be left until later;
some of them like closures (which requires keeping around local variables
from dead fibres) really need the new interpreter and garbage collection,
but can just be left until later.
I have in my head the rough order that I will implement things; I'm just
going to leave the undecided parts until later, or implement some simple
solution as a placeholder for the final behaviour. One thing that doesn't
really require anything undecided is to add "immediate" scripts, which
return a value like required XP to level without waiting.

Maybe we are being too imperative-minded. In many engines you would define
various events that an object can receive, all handled by different
scripts. I wonder if there is an engine with such a system that also have
the equivalent of our 'wait'. Maybe an engine where the event handlers can
be coroutines (eg. generators in python). That's not really the same thing
though.
This is particularly relevant to the plan to add "map script", "npc
script", etc, as alternative to "plotscript"; if these are methods on an
NPC or whatever it seems a bit odd to have an independent lifespan.


> I am excited about script multitasking. :)
>
> ---
> James
>
>
> On Sat, Sep 3, 2016 at 10:56 AM, Ralph Versteegen <teeemcee at gmail.com>
> wrote:
>
>>
>> I was working on the new script intepreter, but got distracted and
>> have now resumed work on script fibres/multitasking (turns out it's
>> related to script profiling).  However the roadblock to working on this is
>> that it requires making tricky decisions about how fibres will act, so
>> prepare for rambling without concluding anything.
>>
>> [To recap: There will be multiple lists of script fibres
>> (coroutines/green threads, each of which is a stack of called scripts
>> that can 'wait' independently). Each group is ordered (the fibres run
>> in a certain order until hitting a wait). There are at least two lists
>> of fibres: the existing main group that runs before the game logic
>> (hero, NPC movement, etc), and the "per-frame" group that runs
>> immediately before drawing the screen (where you should put scripts
>> for parallax and so forth). Battles will effectively also have
>> separate fibre groups, though it would be equivalent to just suspend
>> all out-of-battle fibres.]
>>
>> The big undecided issue is determining the order in which fibres execute
>> and other issues with suspending them.
>>
>> Currently:
>> 1) Newly triggered scripts pause all existing ones
>> 2) Multiple scripts triggered on the same tick run in some order
>>    according to historical accident, which is sometimes weird, like
>>    on-keypress scripts running before the new game script, and the
>>    priority of a map autorun script depends on how it is triggered
>>    (new game, stepping on a door, use door textbox conditional,
>>    "teleport to map" are all different!)
>> 3) If a script is triggered due to something another does, like "use
>>    menu item" or "advance textbox", then that script runs immediately.
>> 4) But a script triggered while not already inside the script
>>    interpreter doesn't run until the *next* tick, unless it's either
>>    an on-keypress, menu item, or menu close script, which get
>>    triggered early so run the same tick.
>>
>> In practice 2) and 4) don't seem to be that much of a problem, except
>> for map autorun scripts.  The fact that those are delayed for a tick
>> means we had to add the hacks of delaying music changes and screen
>> fade ins by an extra tick to let the script run first, and made the
>> queued fades cancellable.)  I also hate the fact that some game logic
>> (that for user-editable menus) happens before the script interpreter,
>> and everything else happens afterwards, which causes 4). Maybe that
>> can be fixed at the same time.
>>
>> Translating behaviours 1) to 4) to fibres would mean that new fibres
>> always get inserted at the front of the fibre group, and also that
>> when a script gets triggered while inside the interpreter, the
>> interpreter temporarily switches to that fibre until it waits before
>> resuming the normal order. This would probably slightly reduce the
>> difficulty of translating existing scripts to multitasking, because at
>> least the order doesn't change.
>>
>> But since multitasking is a major change, it's an opportunity to
>> switch to something more organised.  Since there will eventually be
>> commands for reordering fibres anyway, we don't need to do more than
>> provide a sane default.  The scheduling behaviours you might expect:
>> - a script triggered to initialise something like a map or the game
>>   should run before other scripts for that map.
>> - if you have a whole lot of npc movement (AI) scripts, you probably
>>   want them to all run together, rather than possibly some before and
>>   some after a main logic loop script.  For example, the "create NPC"
>>   command might start a new npc AI fibre, and you probably don't want
>>   that to suspend your current script before you can even call "set
>>   NPC position".
>>   (In reality, it seems best if NPC scripts aren't started until the
>>   engine does NPC movement processing)
>> - a lot of scripts will be cutscenes, and want top priority, so they
>>   can pause other fibres as needed
>> - most scripts will just have an immediate effect, like incrementing a
>>   global, and these should also have priority over already running
>>   scripts like your main loop
>>
>> One solution might be to let you optionally assign numerical
>> priorities to fibres, or otherwise (the default) it is set to always
>> run before anything else. This could be an option in Custom next to
>> every script trigger. Then, when a script is triggered:
>> - if it has a numerical priority, insert it in the list of fibres in
>>   the right spot.
>> - if it doesn't, put it in the front
>> - if we're already in the script interpreter, and it's ahead of the
>>   current script, then as a special case this tick, immediately
>>   execute it instead of delaying it for a tick.  Otherwise, we wait
>>   until it gets its normal turn.
>>
>> Or maybe when a script is triggered, e.g. by a textbox, it should be
>> run immediately instead of inserted into a fibre group to be run after
>> the engine has finished its logic. If it waits rather than returning,
>> it can go to the front of the main fibre group, to run before the
>> engine logic next tick. This also gives the script 1 tick to place
>> itself in some other fibre group or some other position in the order,
>> and matches how you would expect an event-based game engine to
>> work.
>>
>> But then there's the need to provide a way to transition an existing
>> game with a lot of scripts depending on the current suspension
>> behaviour to multitasking.  The solution I wrote on the wiki long ago
>> (that page needs a major overhaul) is to add "blocking script" as an
>> alternative to "plotscript". Only one blocking script can be active at
>> a time.  And I guess only a blocking script would be delayed a tick
>> instead of running immediately.
>>
>> And what about commands that cause implicit waits? It seems dubious to
>> make them suspend all other script fibres too. It would be possible to
>> add a backcompat bit to remove implicit waits (or combine it with
>> the bit to enable multitasking, if any).
>>
>
Regarding implicit waits and running scripts immediately when they are
triggered:
Invoking any engine code from within the interpreter is safe except for
something
that resets the game or loads the game, which will try to reset the
interpreter.
On the other hand, running a script at the point that it's triggered can
result in
almost arbitrary side effects that the code triggering the script may not
expect.
All such code would have to be audited. That ought to be doable. One
possibility
is to trigger scripts but not start them until a little, whether at the end
of the section
of code that's iterating over all NPCs or whatever, or until all the game
logic for
a tick is finished. I now definitely feel that waiting a whole tick before
running triggered
scripts is a bug that we need to fix.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.motherhamster.org/pipermail/ohrrpgce-motherhamster.org/attachments/20160906/524c3c9d/attachment.htm>


More information about the Ohrrpgce mailing list