Seemann 231 Posted October 4, 2015 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 500ADD_SCORE player 100WAIT 250END_CUSTOM_SCRIPTit would compile to 1: 5002: 0 1001: 2503:with the following lookup table (pseudo code): 1=wait2=add_score3=end_custom_scriptCLEO 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 1=00012=01093=0A93We 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). Quote Share this post Link to post Share on other sites
Wesser 345 Posted October 4, 2015 (edited) 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: [COMMAND]0A51=0,commandConsequently, 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; ... do { ... 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. Edited October 5, 2015 by Wesser Quote Share this post Link to post Share on other sites
LINK/2012 1,549 Posted November 13, 2016 (edited) So, I've been working on a GTA3script compiler for a few months now and would certainly like to implement something along the lines of what has been discussed here.In fact, I've formalized things a bit up, and would like to listen to divergences, alternatives and suggestions. Regarding Custom Header Chunks. Regarding Custom Commands Using Hashes. Regarding how CLEO4 should behave as an extension to GTA3script. So far I have collected lots of insights from Wesser, NTAuthority and Silent. So, the work in those drafts aren't mine by any means, instead they're supposed to be a collection of whatever the community ends up agreeing upon.Although the features above are the most important ones, there are a few other extensions to the language which I would like to see discussed as well: REQUIRE DEFINE The addition of hexadecimal integer literals. The additional of a semantic (perhaps a command) for a similar purposes as the Sanny Builder's HEX...END blocks. Relaxing REPEAT to allow variables in the times argument. The addition of ELSEIF to complement IF. And to conclude, a little script to sum things up a bit Edited November 13, 2016 by LINK/2012 Quote Share this post Link to post Share on other sites
fastman92 2,193 Posted November 13, 2016 (edited) Contact me and I can tell you something about the GTA LCS and VCS SCM. For which I have made a simple compiler. Edited November 13, 2016 by fastman92 Quote Share this post Link to post Share on other sites
goodidea82 327 Posted November 21, 2016 (edited) "Adding custom commands is always carefully considered as it costs a 15-bit command id. And, since command ids are essentially progressive numbers, the risk of collisions is quite high, if not unavoidable." Do I understand correctly, if I implement a custom opcode with a new unused ID using the cleo library (in a so-called cleo plugin with .cleo extension), then eventually there will be a hash collision and a different opcode will be called instead? (Background: I have code that generates opcode implementations for new opcodes in the ID range 1000-1FFF and negated versions in the range 9000-9FFF) Suggestion about the code example. Using upper case letters will get very tedious. It would be better to use lower case letter for keywords and known names and let a syntax-aware editor do the visual appealing. Edited November 21, 2016 by goodidea82 Quote Share this post Link to post Share on other sites
LINK/2012 1,549 Posted November 22, 2016 (edited) "Adding custom commands is always carefully considered as it costs a 15-bit command id. And, since command ids are essentially progressive numbers, the risk of collisions is quite high, if not unavoidable." Do I understand correctly, if I implement a custom opcode with a new unused ID using the cleo library (in a so-called cleo plugin with .cleo extension), then eventually there will be a hash collision and a different opcode will be called instead? (Background: I have code that generates opcode implementations for new opcodes in the ID range 1000-1FFF and negated versions in the range 9000-9FFF) You misunderstood it, yes. Command ids are what we currently call opcodes. What I meant is the opcode range 0000-7FFF is too small. Not only that, the way we register opcodes at the moment can very easily make two people to pick the same opcode ids as humans are not good at randomness. Suggestion about the code example. Using upper case letters will get very tedious. It would be better to use lower case letter for keywords and known names and let a syntax-aware editor do the visual appealing. That's Rockstar Vision . Everything is case-insensitive, but a conventional coding style can be observed from R* sources: commands and constants in uppercase and variables in lowercase. See here if you wanna learn further. Edited November 22, 2016 by LINK/2012 Quote Share this post Link to post Share on other sites
goodidea82 327 Posted November 22, 2016 (edited) I guess there is still some confusion what we're talking about. "Do I understand correctly" - "You misunderstood it, yes" ? You mean "...the risk of collisions---with IDs defined by different people---is quite high,.."? Here two people have used the same command ID for defining their custom opcode. Or, you mean that if I define opcode 1ABC, then a hash is created in the SCM engine (let say 123456) and it has a collision with another opcode, e.g., 2ABC (same hash: 123456). When I call 1ABC, then actually 2ABC will be called because the hashes collide? Edited November 22, 2016 by goodidea82 Quote Share this post Link to post Share on other sites
LINK/2012 1,549 Posted November 23, 2016 No hashes are involved in the current script engine, just command ids (0000 for NOP, 0001 for WAIT, 0002 for SHAKE_CAM...). Indeed, I'm not talking about hash collisions there, perhaps a better term could be used to avoid confusion. The collision I meant is with the opcode number itself, like you register 2ABC and another plugin also registers 2ABC. Quote Share this post Link to post Share on other sites