View Page Source

Revision (current)
Last Updated by FatRatKnight on 10/5/2014 7:47 PM
Back to Page

%%TOC%%

This supplementary chapter will deal with a trick for allowing more than one script to run at once, by simply loading up each file one at a time, in any arbitrary order, and none of the scripts have to know the others even exist. The way lsnes is structured allows for this simple trick to run multiple scripts in a chain.

!!A Simple on_paint Chain
%%SRC_EMBED lua
local OldPaint= on_paint or function() end   -- Make a local reference to on_paint
function on_paint(non_synth)
    OldPaint(non_synth)       -- Call the old display
    -- Add your own code here
end
%%END_EMBED

You can run any number of these scripts.

In case it isn't obvious from just reading it, this piece of code defines a ''local'' OldPaint and gives it the ''global'' __on_paint__ (or an empty function if there is no ''global'' __on_paint__). It then replaces ''global'' __on_paint__ with a new function that immediately calls our ''local'' OldPaint, which thankfully refers to the function we now just removed out of ''global'' __on_paint__. This means the old stuff we're displaying is still getting displayed, while we can add new stuff to it as we wish.

In this case, it is vital to use the ''local'' keyword for OldPaint (or some other name you like), as without such, the moment you try to chain any script in, it will replace a ''global'' OldPaint with the previous __on_paint__, and now the old script is calling itself in an endless recursion (and hit a stack overflow). By using ''local'', you forbid any new scripts you load from referring to ''local'' values used in a previous script, and it will define a separate ''local'' OldPaint for every new script in the chain.

!!Working with Gaps
Somewhere in our chain, a script is making use of some gap function, such as __gui.right_gap__. If we have another script that makes use of the same gap, we may end up overlapping our displays. It is often undesirable to have multiple texts on the same spot in the screen, and also inconvenient to edit multiple different scripts to have their displays play nice with each other.

If you're going to chain scripts, it may be best to use delta_gap functions, such as __gui.delta_right_gap__, and read the value it returns. The delta_gap will add an additional gap on top of what's there, and if you use the number to position your display, it will fit comfortably in the new spot.

Also recall the left and top gap functions will return positive values. The coordinates that write to this gap need to be negative, so don't forget to subtract rather than add these gaps.

%%SRC_EMBED lua
local OldPaint= on_paint or function() end
function on_paint(non_synth)
    OldPaint(non_synth)

    local Right,Bottom= gui.resolution()     -- Find our screen edges

    local X= Right + gui.delta_right_gap(96) -- X now points to the left edge of our added gap
    gui.text(X,1,"Hello World.")             -- Hello world. Nice to meet you from this gap.

    X= -gui.delta_left_gap(40) - 40          -- Left side gap, for comparison
    gui.text(X,1,"Left.")
end
%%END_EMBED

!!Other Callbacks
In most cases, the only thing you have to worry about is making sure to pass all parameters along to the next function in the chain. However, anything dealing with input could easily interfere.

For __on_keyhook__, if you plan to chain the script, then it's easily possible that another script may have need of other keys. If your script only needs one key, one could just call __input.keyhook__ once and expect only that key to be used. If the script is chained, suddenly the assumption that only that key will activate __on_keyhook__ will fail. Always add code to make sure that the key you wanted is the one being pressed. In the odd case where your script dynamically enable or disable keyhooks, there aren't any good detection methods to ensure you avoid disabling a keyhook needed by chained scripts other than using a consistently named global variable.

For __on_input__, there is the possibility the script can feed lsnes controller input. Multiple scripts trying to affect on_input independently will only let the latest set functions decide the input. Again, detection methods between scripts is best handled by a consistently named global variable.

Finally, while this isn't unique to any callback, any writes to memory or hostmemory might need to be accounted for. If your scripts are all information scripts that only read, there's no problem, but if you're using a few cheat scripts, there's a possibility of conflict between scripts. The latest write goes through.