[Ohrrpgce] Script fibres/multitasking (again)

Ralph Versteegen teeemcee at gmail.com
Sat Sep 3 10:56:09 PDT 2016


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).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.motherhamster.org/pipermail/ohrrpgce-motherhamster.org/attachments/20160904/767c3925/attachment-0001.htm>


More information about the Ohrrpgce mailing list