Jump to content

» «

Generic SA SCM Documentation

121 replies to this topic
  • Seemann


  • GTA Mods Staff
  • Joined: 03 Sep 2004
  • Russia
  • Best Tool 2013 "Sanny Builder"
    Contribution Award [Mods]
    Helpfulness Awards [Mods]


Posted 04 October 2015 - 02:42 PM

We could implement a system similar to the objects segment in the scm format. The compiler builds a lookup table for each script command used and compiles a script with relative indices in that table rather than actual opcodes. Consider this example:

We have a simple code
WAIT 500
ADD_SCORE player 100
WAIT 250
it would compile to
1: 500
2: 0 100
1: 250
with the following lookup table (pseudo code):
CLEO when initialised knows all the original opcodes under their names+numbers (wait is 0001, jump is 0002, etc) and all the custom handlers (.cleo plugins). It reads the lookup table and replaces string names with actual opcodes
We hook the CRunningScript::Process() and replace an index read from the script with the opcode from the lookup table, so everything works as usual.
So, CLEO plugins must expose custom opcodes with string names instead of indices. And the compiler should be able to read the plugins export before compiling to collect custom opcodes names and number of parameters (if we don't want to manually update the INI).
  • Wesser likes this

  • Wesser

    The complexity simplifier, the efficiency optimizer.

  • Feroci
  • Joined: 19 Aug 2006
  • Unknown
  • Contribution Award [Mods]


Posted 04 October 2015 - 11:21 PM Edited by Wesser, 05 October 2015 - 06:50 PM.

Yeah, it's more or less what I was trying to explain but I honestly didn't think about used objects (as of R*' denomination).

Modifying the script buffer by overwriting the referenced command numbers would require accessing the lookup table only every time a user-defined command is being used and not when any command is being read by the scripting engine, which can occur multiple times if inside a loop. Nonetheless, even though the way you exposed is slight inefficient it is actually hook-friendly and so recommended: injecting SCM codes into a script featuring new commands would be far less problematic because knowing the table indices would be enough for the hooker, who won't be forced to organize the script such that command numbers get updated manually at runtime.

GTA3script compilers will have no issue to handle the script compilation at each command addition since their definition is what matters. Instead, SB compilers and similar should provide support for script dependent lists (enumerating only the new commands) without the need to touch the standard configuration.

It's too late here, I apologize for my potential superficiality.

EDIT: In summary, assuming we would like to take advantage of additional commands, we would have to build a script.lst file holding the new commands list beginning from the last free index, in this human-readable format:
Consequently, a compiler's directive should include the aforesaid list by replicating $OPCODE behaviour in this manner:
{$NEWOPCODE script.lst}
Its variant can also be enhanced to accomodate the new syntax used for individual command definitions by establishing another directive:
{$NEWOPCODE COMMAND 0A51=0,command}
At compilation stage, the compiler will generate a hypotetical script.no (New Opcodes) file containing only the command string names sorted by the command index which must be progressive before compiling. At startup, CLEO will collect the POC (ProcessOneCommand) of each new command in the order they are registered by means of loaded plugins. At script launch, if the associated .no file is present, CLEO will generate a context dependent lookup table by swapping string names with indices and give the task to select the belonging list of the processed command to CRunningScript::ProcessOneCommand, as the following pseudocode demonstrates:
class CRunningScript
    struct CommandID
        short m_sIndex : 7;
        short m_bNotFlag : 1;

    short *m_pNewCommandsAssoc;

    void ProcessOneCommand(void);


void CRunningScript::ProcessOneCommand(void)
    CommandID commandID;
    short sCommandIndex;

        sCommandIndex = commandID.m_sIndex;
    while((m_pNewCommandsAssoc && sCommandIndex > 2640
         ? g_aNewCommandsArray[m_pNewCommandsAssoc[sCommandIndex - 2641]]
         : g_aCommandsPOCArray[sCommandIndex / 100])(sCommandIndex));

The neat thing is the compatibility of the scripts which won't avail of the questioned feature will never get lost.

1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users