Skip to content

Instantly share code, notes, and snippets.

@thelink2012
Last active December 5, 2016 16:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thelink2012/66de0884e76d281baa08b1f878d1d08e to your computer and use it in GitHub Desktop.
Save thelink2012/66de0884e76d281baa08b1f878d1d08e to your computer and use it in GitHub Desktop.
  • Feature Name: commands-oat
  • Start Date: 11/11/2016

Knowledge of the SCM format is assumed.

Summary

Proposal for a means of compiling commands by associating them with hashes.

Motivation

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.

Detailed design

This design of this feature is pretty much based on a previous discussion on GTAForums about the matter.

The premise is that custom commands, when compiled, should not have a fixed command id. Instead, they should compile into a ordinal id, which have a corresponding entry at the script header. Such header entry contains the command hash and, optionally, the command name, which the runtime will use to find the correct interpreter for the command.

As the hashing function, the Bob Jenkins One-at-a-Time algorithm was choosen. No in-depth research has been performed, but since the designers of RAGE choose this function for their command names, which have the same nature as the ones being hashed here, this should be a good pick. No collision is produced with San Andreas default commands together with CLEO4 commands, and the distribution seems quite nice as well.

All the command names shall be hashed in uppercase, otherwise the hash is ill-formed.

By following the custom-headers specification, the custom commands header should be as follow:

(02 00 01)h + 32 bit int        Jump to next segment (may be a local jump)
(FF 7F FE 00 00)h               Custom headers magic number
(4F 41 54 43)h                  Signature of the header ('OATC')
16-bit int                      The command id that begins the custom commands ordinal id
16-bit int                      The number of ordinal ids used in the script
for (number of ordinal ids):
    (00 00 00 00)h              Field reserved for the runtime to use internally as it see fits
    32 bit int                  The One-at-a-Time hash for the command
    32 bit int                  Optional offset to the null-terminated command name
                                The offset is relative to the OATC fourcc. Use (00 00 00 00)h to ignore.

The runtime and compiler implementation are free to ignore the null-terminated command-name and use only the hash value.

Example

Take the following script:

WAIT 0
WRITE_MEMORY 0 1 0 FALSE
TERMINATE_THIS_CUSTOM_SCRIPT

Usually this code would be compiled to the following bytecode:

01 00 04 00                     // fixed id 0001h
8C 0A 04 00 04 01 04 00 04 00   // fixed id 0A8Ch
93 0A                           // fixed id 0A93h

By using this specification, it should, however, compile to something along the lines of

01 00 04 00                     // fixed id 0001h
05 00 04 00 04 01 04 00 04 00   // ordinal id 0005h
06 00                           // ordinal id 0006h

Then, the header would look like:

[...]
02 00 01 ?? ?? ?? ?? FF 7F FE 00 00 // custom header begin
4F 41 54 43                         // FOURCC 'OATC'
05 00                               // All commands after, and including, 0005h should use the ordinals table
02 00                               // Two ordinals were used
00 00 00 00                         // #1
1E 35 CC C3                         // #1 One-at-a-Time hash for WRITE_MEMORY
00 00 00 00                         // #1
00 00 00 00                         // #2
1C 9E 0E A7                         // #2 One-at-a-Time hash for TERMINATE_THIS_CUSTOM_SCRIPT
00 00 00 00                         // #2
[...]

Although the starting ordinal id was set to 0005h to simplify the example, a compiler implementing this specification should try starting from an unassigned command id.

Drawbacks

Why should we not do this?

Alternatives

Any other alternative?

Unresolved questions

  • Should the header be compiled when there are zero custom commands?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment