Difference between revisions of "SCO"

From GTAMods Wiki
Jump to navigation Jump to search
 
(48 intermediate revisions by 10 users not shown)
Line 1: Line 1:
 +
{{TocRight}}
 
'''SCO''' files contain [[GTA 4]]'s game scripts. Its new format replaces old [[SCM|scm]] one.
 
'''SCO''' files contain [[GTA 4]]'s game scripts. Its new format replaces old [[SCM|scm]] one.
  
==File Format==
+
== File Format ==
 
+
A SCO file is laid out into 4 segments. First the [[#Header|header]] containing information about the SCO file. Then the [[#Code Segment|code segment]] which contains the opcodes which govern how the script behaves. The next segment is the [[#Static Variables|static variables]] container which contains enough space to hold the scripts static variables. The last is the [[#Global Variables|global variables]] container, it is unclear what this segment actually does.
A SCO file is layed out into 4 segments. First the Header containing information about the SCO file. Then the Code Segment which contains the opcode's which govern how the script behaves. The next segment is the Local Variable container which contains enough space to hold the local variables. The last is the Global Variable container, which contains enough space to house the global variables, as well as setting them by default.
 
 
 
===Header===
 
  
 +
=== Header ===
 
There are 2 types of SCO files, an encrypted and unencrypted one. Each file however shares the same unencrypted header structure, and you can use this to determine which type of SCO file you are dealing with. The size of this header is '''24 bytes'''.
 
There are 2 types of SCO files, an encrypted and unencrypted one. Each file however shares the same unencrypted header structure, and you can use this to determine which type of SCO file you are dealing with. The size of this header is '''24 bytes'''.
  
 
  4b - CHAR[4]/UINT32 - SCO Identifier
 
  4b - CHAR[4]/UINT32 - SCO Identifier
 
  4b - UINT32 - Code Size
 
  4b - UINT32 - Code Size
  4b - UINT32 - Local Var Size
+
  4b - UINT32 - Static Var Count
  4b - UINT32 - Global Var Size
+
  4b - UINT32 - Global Var Count
 
  4b - UINT32 - Script Flags
 
  4b - UINT32 - Script Flags
 
  4b - UINT32 - Signature
 
  4b - UINT32 - Signature
  
The SCO Identifier will be "SCR\r" (or 0xD524353) in an unencrypted version, and "scr"+0xE (or 0xE726373) in an encrypted version.
+
The SCO Identifier will be "SCR\r" (or 0xD524353) in an unencrypted version, and "scr"+0xE (or 0xE726373) in an encrypted version. To decrypt an encrypted version you must decrypt each segment (except the header) separately using GTA IV's AES [[Cryptography]].
 
The Code Size refers to the amount of bytes the code section takes up.
 
The Code Size refers to the amount of bytes the code section takes up.
The Local Var Size refers to the amount of local variables the SCO file contains. The segment for local variables starts at the end of Header + Code Size, and continues for 4x the local variable size (due to the local variables being stored in 4 byte segments).
+
The Static Var Count refers to the amount of static variables the SCO file contains. The segment for static variables starts at the end of Header + Code Size, and continues for 4x the static variable count (due to the static variables being stored in 4 byte's each).
The Global Var Size refers to the amount of global variables the SCO file contains. The segment for global variables starts at the end of Header + Code Size + Local Var Size * 4, and continues for 4x the global variable size (due to the global variables being stored in 4 byte segments).
+
The Global Var Size refers to the amount of global variables the SCO file contains. The segment for global variables starts at the end of Header + Code Size + Static Var Count * 4, and continues for 4x the global variable count (due to the global variables being stored in 4 byte's each).
The Script Flags are boolean bits which are currently unexplained.
+
The Script Flags appear to correspond to how many arguments you will pass to the script when starting using the native START_NEW_SCRIPT_WITH_ARGS
 
The Signature only differs in navgen_main, but could possibly set the script priority.
 
The Signature only differs in navgen_main, but could possibly set the script priority.
  
 
===Code Segment===
 
===Code Segment===
 
 
The Code Segment contains the opcodes which govern the scripts behaviour.
 
The Code Segment contains the opcodes which govern the scripts behaviour.
  
 
====Opcodes====
 
====Opcodes====
 +
Opcodes can have varying sizes, but all opcodes are identified by their first byte. There are 79 opcodes which can occur and any opcode above 80 is a Push opcode which pushes '''its own number - 96''' onto the stack. For example, opcode 100 will push 4 onto the stack. Opcodes 76,77,78 deal with XLive protected buffers and are available on the PC platform only. Undefined opcodes (i.e. opcode 79), will cause a forceful abort of the script execution.
  
Opcodes can have varying sizes, but all opcodes are identified by their first byte. There are 80 opcodes which can occur, any opcode above 80 is a Push opcode which pushes '''it's own number - 96''' onto the stack.
+
{|class="wikitable mw-collapsible"
 
 
{|{{Prettytable}} class="collapsible"
 
 
!ID
 
!ID
 
!Name
 
!Name
 
!Description
 
!Description
 
!Length
 
!Length
 +
!
 +
|-
 +
|0|| NOP || No operation || 1 byte
 +
|-
 +
|1|| IADD || Adds the top 2 items on the stack || 1 byte
 +
|-
 +
|2|| ISUB || Subtracts the top 2 items on the stack || 1 byte
 +
|-
 +
|3|| IMUL || Multiplies the top 2 items on the stack || 1 byte
 +
|-
 +
|4|| IDIV || Divides the top 2 items on the stack || 1 byte
 +
|-
 +
|5|| IMOD || Mods the top 2 items on the stack || 1 byte
 +
|-
 +
|6|| INOT || Checks the first item on the stack to see if it equals 0 || 1 byte
 
|-
 
|-
|0|| Nop || No operation || 1 byte
+
|7|| INEG || Reverses the sign on the item on the top of the stack || 1 byte
 
|-
 
|-
|1|| Add || Adds the top 2 items on the stack || 1 byte
+
|8|| IEQ || Compares the top 2 integers on the stack to see if they are equal || 1 byte
 
|-
 
|-
|2||Sub || Subtracts the top 2 items on the stack || 1 byte
+
|9|| INE || Compares the top 2 integers on the stack to see if they are not equal || 1 byte
 
|-
 
|-
|3|| Mul || Multiplies the top 2 items on the stack || 1 byte
+
|10|| IGT || Compares the top 2 integers on the stack to see if the first one is greater than the second one || 1 byte
 
|-
 
|-
|4|| Div || Divides the top 2 items on the stack || 1 byte
+
|11|| IGE || Compares the top 2 integers on the stack to see if the first one is greater than or equal to the second one || 1 byte
 
|-
 
|-
|5|| Mod || Mods the top 2 items on the stack || 1 byte
+
|12|| ILT || Compares the top 2 integers on the stack to see if the first one is less than the second one || 1 byte
 
|-
 
|-
|6|| IsZero || Checks the first item on the stack to see if it equals 0 || 1 byte
+
|13|| ILE || Compares the top 2 integers on the stack to see if the first one is less than or equal to the second one || 1 byte
 
|-
 
|-
|7|| Neg || Reverses the sign on the item on the top of the stack || 1 byte
+
|14|| FADD || Adds the top 2 floats on the stack || 1 byte
 
|-
 
|-
|8|| CmpEq || Compares the top 2 integers on the stack to see if they are equal || 1 byte
+
|15|| FSUB || Subtracts the top 2 floats on the stack || 1 byte
 
|-
 
|-
|9|| CmpNe || Compares the top 2 integers on the stack to see if they are not equal || 1 byte
+
|16|| FMUL || Multiplies the top 2 floats on the stack || 1 byte
 
|-
 
|-
|10|| CmpGt || Compares the top 2 integers on the stack to see if the first one is greater than the second one || 1 byte
+
|17|| FDIV || Divides the top 2 floats on the stack || 1 byte
 
|-
 
|-
|11|| CmpGe || Compares the top 2 integers on the stack to see if the first one is greater than or equal to the second one || 1 byte
+
|18|| FMOD || Mods the top 2 floats on the stack || 1 byte
 
|-
 
|-
|12|| CmpLt || Compares the top 2 integers on the stack to see if the first one is less than the second one || 1 byte
+
|19|| FNEG || Reverses the sign on the first float on the stack || 1 byte
 
|-
 
|-
|13|| CmpLe || Compares the top 2 integers on the stack to see if the first one is less than or equal to the second one || 1 byte
+
|20|| FEQ || Compares the top 2 floats on the stack to see if they are equal || 1 byte
 
|-
 
|-
|14|| AddF || Adds the top 2 floats on the stack || 1 byte
+
|21|| FNE || Compares the top 2 floats on the stack to see if they are not equal || 1 byte
 
|-
 
|-
|15|| SubF || Subtracts the top 2 floats on the stack || 1 byte
+
|22|| FGT || Compares the top 2 floats on the stack to see if the first one is greater than the second one || 1 byte
 
|-
 
|-
|16|| MulF || Multiplies the top 2 floats on the stack || 1 byte
+
|23|| FGE || Compares the top 2 floats on the stack to see if the first one is greater than or equal to the second one || 1 byte
 
|-
 
|-
|17|| DivF || Divides the top 2 floats on the stack || 1 byte
+
|24|| FLT || Compares the top 2 floats on the stack to see if the first one is less than the second one || 1 byte
 
|-
 
|-
|18|| ModF || Mods the top 2 floats on the stack || 1 byte
+
|25|| FLE || Compares the top 2 floats on the stack to see if the first one is less than or equal to the second one || 1 byte
 
|-
 
|-
|19|| NegF || Reverses the sign on the first float on the stack || 1 byte
+
|26|| VADD || Adds the top 2 Vectors{{Ref|1}} on the stack || 1 byte
 
|-
 
|-
|20|| CmpEqF || Compares the top 2 floats on the stack to see if they are equal || 1 byte
+
|27|| VSUB || Subtracts the top 2 Vectors{{Ref|1}} on the stack || 1 byte
 
|-
 
|-
|21|| CmpNeF || Compares the top 2 floats on the stack to see if they are not equal || 1 byte
+
|28|| VMUL || Multiplies the top 2 Vectors{{Ref|1}} on the stack || 1 byte
 
|-
 
|-
|22|| CmpGtF || Compares the top 2 floats on the stack to see if the first one is greater than the second one || 1 byte
+
|29|| VDIV || Divides the top 2 Vectors{{Ref|1}} on the stack || 1 byte
 
|-
 
|-
|23|| CmpGeF || Compares the top 2 floats on the stack to see if the first one is greater than or equal to the second one || 1 byte
+
|30|| VNEG || Reverses the sign on the first vector{{Ref|1}} on the stack || 1 byte
 
|-
 
|-
|24|| CmpLtF || Compares the top 2 floats on the stack to see if the first one is less than the second one || 1 byte
+
|31|| IAND || Performs an [[Wikipedia:Logical_conjunction|And]] operation to the first 2 integers on the stack || 1 byte
 
|-
 
|-
|25|| CmpLeF || Compares the top 2 floats on the stack to see if the first one is less than or equal to the second one || 1 byte
+
|32|| IOR || Performs an [[Wikipedia:Logical_disjunction|Or]] operation to the first 2 integers on the stack || 1 byte
 
|-
 
|-
|26|| AddVec || Adds the top 2 Vectors{{Ref|1}} on the stack || 1 byte
+
|33|| IXOR || Performs a [[Wikipedia:XOR|Xor]] operation to the first 2 integers on the stack || 1 byte
 
|-
 
|-
|27|| SubVec || Subtracts the top 2 Vectors{{Ref|1}} on the stack || 1 byte
+
|34|| J || Jumps to a section of code, using the next 4 bytes after the opcode as a placement || 5 bytes
 
|-
 
|-
|28|| MulVec || Multiplies the top 2 Vectors{{Ref|1}} on the stack || 1 byte
+
|35|| JZ || Jumps to a section of code if the top of the stack is 0, using the next 4 bytes after the opcode as a placement || 5 bytes
 
|-
 
|-
|29|| DivVec || Divides the top 2 Vectors{{Ref|1}} on the stack || 1 byte
+
|36|| JNZ || Jumps to a section of code if the top of the stack is 1, using the next 4 bytes after the opcode as a placement || 5 bytes
 
|-
 
|-
|30|| NegVec || Reverses the sign on the first vector{{Ref|1}} on the stack || 1 byte
+
|37|| I2F || Converts the top integer on the stack to a float, and puts that float on the stack || 1 byte
 
|-
 
|-
|31|| And || Performs an [[Wikipedia:Logical_conjunction|And]] operation to the first 2 integers on the stack || 1 byte
+
|38|| F2I || Converts the top float on the stack to an integer, and puts that integer on the stack || 1 byte
 
|-
 
|-
|32|| Or || Performs an [[Wikipedia:Logical_disjunction|Or]] operation to the first 2 integers on the stack || 1 byte
+
|39|| F2V || Converts the top float into a Vector{{Ref|1}} containing 3 instances of the same float, and pushes the pointer to that Vector{{Ref|1}} onto the top of the stack || 1 byte
 
|-
 
|-
|33|| Xor || Performs a [[Wikipedia:XOR|Xor]] operation to the first 2 integers on the stack || 1 byte
+
|40|| PUSH_CONST_U16 || Pushes a short onto the stack, the short is defined in the next 2 bytes after the opcode || 3 bytes
 
|-
 
|-
|34|| Jump || Jumps to a section of code, using the next 4 bytes after the opcode as a placement || 5 bytes
+
|41|| PUSH_CONST_U32 || Pushes an int onto the stack, the integer is defined in the next 4 bytes after the opcode || 5 bytes
 
|-
 
|-
|35|| JumpFalse || Jumps to a section of code if the top of the stack is 0, using the next 4 bytes after the opcode as a placement || 5 bytes
+
|42|| PUSH_CONST_F || Pushes a float onto the stack, the float is defined in the next 4 bytes after the opcode. Performs exactly the same as Push || 5 bytes
 
|-
 
|-
|36|| JumpTrue || Jumps to a section of code if the top of the stack is 1, using the next 4 bytes after the opcode as a placement || 5 bytes
+
|43|| DUP || Duplicates the first item on the stack, and pushes it back onto the stack || 1 byte
 
|-
 
|-
|37|| ToF || Converts the top integer on the stack to a float, and puts that float on the stack || 1 byte
+
|44|| DROP || Pops the top item off the stack || 1 byte
 
|-
 
|-
|38|| FromF || Converts the top float on the stack to an integer, and puts that integer on the stack || 1 byte
+
|45|| NATIVE || Calls a [[native function]]. The number of arguments for the native to take is defined in the next byte after the opcode. The number of return values is defined in the byte after that (it is always 1 or 0). The next 4 bytes are the hash of the native's name. || 7 bytes
 
|-
 
|-
|39|| VecFromF || Converts the top float into a Vector{{Ref|1}} containing 3 instances of the same float, and pushes the pointer to that Vector{{Ref|1}} onto the top of the stack || 1 byte
+
|46|| CALL || Calls a function within the script, and puts the return address on top of the stack. The location of the function is defined in the next 4 bytes after the opcode || 5 bytes
 
|-
 
|-
|40|| PushS || Pushes a short onto the stack, the short is defined in the next 2 bytes after the opcode || 3 bytes
+
|47|| ENTER || Indicates the beginning of an internal function. The byte after the opcode indicates the amount of arguments the function takes off the stack, and the next 2 bytes after that indicate the number of variables the function will have to generate on the stack. || 4 bytes
 
|-
 
|-
|41|| Push || Pushes an int onto the stack, the integer is defined in the next 4 bytes after the opcode || 5 bytes
+
|48|| LEAVE || Indicates the end of an internal function. The byte after the opcode indicates the amount of arguments that will have to be popped off the stack, and the next byte after that indicates the stack number of the return address || 3 bytes
 
|-
 
|-
|42|| PushF || Pushes a float onto the stack, the float is defined in the next 4 bytes after the opcode. Performs exactly the same as Push || 5 bytes
+
|49|| LOAD || Pops a pointer off the stack and pushes the value stored in that pointer back onto the stack || 1 byte
 
|-
 
|-
|43|| Dup || Duplicates the first item on the stack, and pushes it back onto the stack || 1 byte
+
|50|| STORE || Pops 2 items off the stack and stores the second item at the location of the first item (the first item being a pointer) || 1 byte
 
|-
 
|-
|44|| Pop || Pops the top item off the stack || 1 byte
+
|51|| STORE_REV || Pops the first item off the stack and peeks at the second item on the stack, then stores the first item at the location pointed to by the second item on the stack || 1 byte
 
|-
 
|-
|45|| CallNative || Calls a [[native function]]. The number of arguments for the native to take is defined in the next byte after the opcode. The number of return values is defined in the byte after that (it is always 1 or 0). The next 4 bytes are the hash of the native's name. || 7 bytes
+
|52|| ARRAY_LOAD || Pops 2 items off the stack, the first and second items being the beginning of the memory of the array and the end of the memory of the array. It then divides the difference of these 2 locations by 4 to get the number of items in the array, after which is pushes these items one by one onto the stack in 4 byte segments || 1 byte
 
|-
 
|-
|46|| Call || Calls a function within the script, and puts the return address on top of the stack. The location of the function is defined in the next 4 bytes after the opcode || 5 bytes
+
|53|| ARRAY_STORE || Pops the first item off the stack to get the address of the array to write to, and then pops the stack off onto that array || 1 byte
 
|-
 
|-
|47|| FnBegin || Indicates the beginning of an internal function. The byte after the opcode indicates the amount of arguments the function takes off the stack, and the next 2 bytes after that indicate the number of variables the function will have to generate on the stack. || 4 bytes
+
|54|| LOCAL_0 || Pushes the pointer to the first function local variable onto the stack. || 1 byte
 
|-
 
|-
|48|| FnEnd || Indicates the end of an internal function. The byte after the opcode indicates the amount of arguments that will have to be popped off the stack, and the next byte after that indicates the stack number of the return address || 3 bytes
+
|55|| LOCAL_1 || Pushes the pointer to the second function local variable onto the stack. || 1 byte
 
|-
 
|-
|49|| RefGet || Pops a pointer off the stack and pushes the value stored in that pointer back onto the stack || 1 byte
+
|56|| LOCAL_2 || Pushes the pointer to the third function local variable onto the stack. || 1 byte
 
|-
 
|-
|50|| RefSet || Pops 2 items off the stack and stores the second item at the location of the first item (the first item being a pointer) || 1 byte
+
|57|| LOCAL_3 || Pushes the pointer to the fourth function local variable onto the stack. || 1 byte
 
|-
 
|-
|51|| RefPeekSet || Pops the first item off the stack and peeks at the second item on the stack, then stores the first item at the location pointed to by the second item on the stack || 1 byte
+
|58|| LOCAL_4 || Pushes the pointer to the fifth function local variable onto the stack. || 1 byte
 
|-
 
|-
|52|| ArrayExplode || Pops 2 items off the stack, the first and second items being the beginning of the memory of the array and the end of the memory of the array. It then divides the difference of these 2 locations by 4 to get the number of items in the array, after which is pushes these items one by one onto the stack in 4 byte segments || 1 byte
+
|59|| LOCAL_5 || Pushes the pointer to the sixth function local variable onto the stack. || 1 byte
 
|-
 
|-
|53|| ArrayImplode || Pops the first item off the stack to get the address of the array to write to, and then pops the stack off onto that array || 1 byte
+
|60|| LOCAL_6 || Pushes the pointer to the seventh function local variable onto the stack. || 1 byte
 
|-
 
|-
|54 -> 61|| LocalVarPtr || Pushes the pointer to a local variable onto the stack || 1 byte  
+
|61|| LOCAL_7 || Pushes the pointer to the eigth function local variable onto the stack. || 1 byte
 
|-
 
|-
|62|| LocalVarPtrEx || Pushes the pointer to a local variable onto the stack where the index is above or equal to 8 || 1 byte
+
|62|| LOCAL || Pushes the pointer to a function local variable onto the stack where the index is above or equal to 8 || 1 byte
 
|-
 
|-
|63|| LocalVar || Pops the index of the local variable off the stack, and pushes a pointer to a script local variable onto the stack || 1 byte
+
|63|| STATIC || Pops the index of the static variable off the stack, and pushes a pointer to the script static variable onto the stack || 1 byte
 
|-
 
|-
|64|| GlobalVar || Pops the index of the global variable off the stack, and pushes a pointer to a script global variable onto the stack || 1 byte
+
|64|| GLOBAL || Pops the index of the global variable off the stack, and pushes a pointer to the public variable onto the stack || 1 byte
 
|-
 
|-
|65|| ArrayRef || Pops the array location, element size and index off the stack, the pushes a pointer to the index of that array onto the stack || 1 byte
+
|65|| ARRAY || Pops the array location, element size and index off the stack, the pushes a pointer to the index of that array onto the stack || 1 byte
 
|-
 
|-
|66|| Switch || Pops the item to compare off the stack, and then jumps to location corresponding to that item. After the opcode byte it contains a byte defining the number of possible entries, and after that the number of possible entries times 8 are taken up with repeating instances of 4 bytes of the index identifier, and 4 bytes of the location to jump to if that index is correct || (Byte after opcode * 8) + 2
+
|66|| SWITCH || Pops the item to compare off the stack, and then jumps to location corresponding to that item. After the opcode byte it contains a byte defining the number of possible entries, and after that the number of possible entries times 8 are taken up with repeating instances of 4 bytes of the index identifier, and 4 bytes of the location to jump to if that index is correct || (Byte after opcode * 8) + 2
 
|-
 
|-
|67|| PushString || Pushes a string onto the stack. The byte after the opcode signals the string length, and for the amount of string length after that byte contains each character of the string || (Byte after opcode)+2
+
|67|| STRING || Pushes a string onto the stack. The byte after the opcode signals the string length, and for the amount of string length after that byte contains each character of the string || (Byte after opcode)+2
 
|-
 
|-
|68|| NullObj || Pushes a pointer to an empty memory container onto the stack || 1 byte
+
|68|| NULL || Pushes a pointer to an empty memory container onto the stack || 1 byte
 
|-
 
|-
|69|| StrCpy || Pops 2 pointers off the stack, and copies the second item to the first item || 1 byte
+
|69|| TEXT_LABEL_ASSIGN_STRING || Pops 2 pointers off the stack, and copies the second item to the first item || 1 byte
 
|-
 
|-
|70|| IntToStr || Pops an integer off the stack and pushes an array to a string representation of that integer onto the stack || 1 byte
+
|70|| TEXT_LABEL_ASSIGN_INT || Pops an integer off the stack and pushes an array to a string representation of that integer onto the stack || 1 byte
 
|-
 
|-
|71|| StrCat || Pops 2 pointers off the stack, and appends the second item to the first item || 1 byte
+
|71|| TEXT_LABEL_APPEND_STRING || Pops 2 pointers off the stack, and appends the second item to the first item || 1 byte
 
|-
 
|-
|72|| StrCatI || Pops 2 items off the stack, and performs a IntToStr on the second item (the integer), then appends that string representation to the first item || 1 byte
+
|72|| TEXT_LABEL_APPEND_INT || Pops 2 items off the stack, and performs a IntToStr on the second item (the integer), then appends that string representation to the first item || 1 byte
 
|-
 
|-
|73|| Catch || Sets up a safe area that has the ability to catch errors || 1 byte
+
|73|| CATCH || Sets up a safe area that has the ability to catch errors || 1 byte
 
|-
 
|-
|74|| Throw || Indicates an area that handles a script error relative to the catch opcode || 1 byte
+
|74|| THROW || Indicates an area that handles a script error relative to the catch opcode || 1 byte
 
|-
 
|-
|75|| StrVarCpy || Pops 3 items off the stack. Copies the third item's memory into the first item's memory with repeating defined by the second item. It then appends a null terminator to the first item's memory || 1 byte
+
|75|| TEXT_LABEL_COPY || Pops 3 items off the stack. Copies the third item's memory into the first item's memory with repeating defined by the second item. It then appends a null terminator to the first item's memory || 1 byte
 
|-
 
|-
|76|| GetProtect || Pops a memory location off the stack and pushes its protection details onto the stack || 1 byte
+
|76|| getxprotect || Pops a memory location off the stack and pushes its XLive unprotected value onto the stack (PC Only) || 1 byte
 
|-
 
|-
|77|| SetProtect || Pops a memory location off the stack as well as its protection details and sets the memory locations new protect details || 1 byte
+
|77|| setxprotect || Pops a memory location off the stack, pops another value off the stack. Protects the second value using XLive and stores the value in the memory location. (PC Only) || 1 byte
 
|-
 
|-
|78|| RefProtect || ? || 1 byte
+
|78|| refxprotect || Pops a memory location off the stack, pops another value off the stack to determine protection flags, and finally pops another value which indicates the number of items to operate on. If the 1st bit of the flags is set, the number of items at the memory location will be XLive unprotected. If the 2nd bit is set, they will be XLive protected instead. (PC Only) || 1 byte
 
|-
 
|-
|79|| Abort || Aborts the script || 1 byte
+
|79|| EXIT || Terminates the script under an error condition || 1 byte
 +
|-
 +
|80 -> 255|| PUSH_CONST_U8 || Pushes an integer onto the stack. The integer is defined by the opcode number - 96. For example opcode 95 would push -1 onto the stack, and opcode 97 would push 1 || 1 byte
 
|}
 
|}
  
Line 190: Line 204:
 
  4b - FLOAT32 - Z
 
  4b - FLOAT32 - Z
  
===Local Variables===
+
===Static Variables===
 
+
This contains the Static Variables in the script. Each static variable is 4 bytes long, and can contain static information in the script file itself.
This contains the Local Variables in the script. Each local variable is 4 bytes long, and can contain static information in the script file itself.
 
  
 
===Global Variables===
 
===Global Variables===
 
+
It is uncertain what this section actually does.
This contains the Global Variables in the script. Each global variable is 4 bytes long, and can contain static information in the script file itself. A global variable remains static until changed via an opcode (or memory editing).
 
 
 
==Tools==
 
 
 
Currently only disassemblers and decompilers are available for the analysis of the SCO scripting language. [[OpenIV]] and [[SparkIV]] contain decompilers and disassemblers built into them.
 
  
 
==High Level Representation==
 
==High Level Representation==
 +
To turn the assembly of a SCO file into a high level representation some factors have to be considered. Arrays and structures can be defined, so it is reasonable to assume there is some kind of typecasting, even if it is only between the following types; [[Wikipedia:Integer_(computer_science)|int]], [[Wikipedia:Floating_point|float]], [[Wikipedia:String_(computer_science)|string]] or a predefined structure. It is interesting to note that opcodes exist to typecast integers and concatenate them directly to strings, this suggests the SCO language has a java like way of handling strings (using + and += for concatenation). The SCO file does not seem to have native support for the notion of classes, however this is not to say they could not be implemented within SCO itself similar to how they are done at a low level in C++.
  
To turn the assembly of a SCO file into a high level representation some factors have to be considered. Arrays and structures can be defined, so it is reasonable to assume there is some kind of typecasting, even if it is only between the following types; [[Wikipedia:http://en.wikipedia.org/wiki/Integer_(computer_science)|int]], [[Wikipedia:http://en.wikipedia.org/wiki/Floating_point|float]], [[Wikipedia:http://en.wikipedia.org/wiki/String_(computer_science)|string]] or a predefined structure. It is interesting to note that StrCpy, StrCat, StrCatInt and IntToStr all exist as opcodes, this makes it feasible to believe that strings may have a Java like syntax when being manipulated, for example to make the string "Hello World 2009" you could perform this kind of operation:
+
== Tools ==
 
+
* [[SC-CL]] – High level *.sco script compiler
<source lang="sco">string testStr = "Hello " + "World " + 2009;</source>
+
* [[Scocl]] &ndash; High level *.sco script compiler by {{U|Alexander Blade}}
 
+
* [http://www.gtaforums.com/index.php?showtopic=481229 SCO Toolbox] &ndash; by {{U|flitskikker}}
This would bring it on par with many other scripting languages such as LUA. When decompiling the script (as in compiling) you can look for certain patterns in the assembly to ascertain what it would like represented at a higher level. Here are some examples:
+
* [[Scone]] &ndash; SCO (Dis-)assembler by {{U|Sacky}}
 
+
* [[OpenIV]] &ndash; contains a built-in decompiler
<source lang="sco_asm">[0x0] : Jump 0x5</source>
+
* [[SparkIV]] &ndash; contains a built-in decompiler
 
 
The first opcode in a SCO file is always a jump to the main() function, where the script starts executing. To get the main prototype you can simply check its FnBegin parameters, for example if you jump to code that has FnBegin 1 1, the main function will begin like this:
 
  
<source lang="sco">void main(var arg1)
+
== See also ==
{
+
* {{icon|trilogy}} [[Mission Scripting (Overview)]] &ndash; introduction to mission scripting in the previous games
var fnlc_1;
+
* {{icon|5}} [[Script_Container|YSC]] - similar script format used in GTA V
}</source>
 
  
As you can see 1 argument has been added, and 1 local variable has been added. A main function will never include a return value, which makes analysing the main() prototype much easier.
+
== External link ==
 +
* {{GTAF|463020|SCO editor development}} &ndash; by {{U|Shadow-Link}}
  
 
{{GTA4-navi}}
 
{{GTA4-navi}}
 
[[Category:Mission Script]][[Category:File Formats]]
 
[[Category:Mission Script]][[Category:File Formats]]

Latest revision as of 17:12, 7 July 2024

SCO files contain GTA 4's game scripts. Its new format replaces old scm one.

File Format

A SCO file is laid out into 4 segments. First the header containing information about the SCO file. Then the code segment which contains the opcodes which govern how the script behaves. The next segment is the static variables container which contains enough space to hold the scripts static variables. The last is the global variables container, it is unclear what this segment actually does.

Header

There are 2 types of SCO files, an encrypted and unencrypted one. Each file however shares the same unencrypted header structure, and you can use this to determine which type of SCO file you are dealing with. The size of this header is 24 bytes.

4b - CHAR[4]/UINT32 - SCO Identifier
4b - UINT32 - Code Size
4b - UINT32 - Static Var Count
4b - UINT32 - Global Var Count
4b - UINT32 - Script Flags
4b - UINT32 - Signature

The SCO Identifier will be "SCR\r" (or 0xD524353) in an unencrypted version, and "scr"+0xE (or 0xE726373) in an encrypted version. To decrypt an encrypted version you must decrypt each segment (except the header) separately using GTA IV's AES Cryptography. The Code Size refers to the amount of bytes the code section takes up. The Static Var Count refers to the amount of static variables the SCO file contains. The segment for static variables starts at the end of Header + Code Size, and continues for 4x the static variable count (due to the static variables being stored in 4 byte's each). The Global Var Size refers to the amount of global variables the SCO file contains. The segment for global variables starts at the end of Header + Code Size + Static Var Count * 4, and continues for 4x the global variable count (due to the global variables being stored in 4 byte's each). The Script Flags appear to correspond to how many arguments you will pass to the script when starting using the native START_NEW_SCRIPT_WITH_ARGS The Signature only differs in navgen_main, but could possibly set the script priority.

Code Segment

The Code Segment contains the opcodes which govern the scripts behaviour.

Opcodes

Opcodes can have varying sizes, but all opcodes are identified by their first byte. There are 79 opcodes which can occur and any opcode above 80 is a Push opcode which pushes its own number - 96 onto the stack. For example, opcode 100 will push 4 onto the stack. Opcodes 76,77,78 deal with XLive protected buffers and are available on the PC platform only. Undefined opcodes (i.e. opcode 79), will cause a forceful abort of the script execution.

ID Name Description Length
0 NOP No operation 1 byte
1 IADD Adds the top 2 items on the stack 1 byte
2 ISUB Subtracts the top 2 items on the stack 1 byte
3 IMUL Multiplies the top 2 items on the stack 1 byte
4 IDIV Divides the top 2 items on the stack 1 byte
5 IMOD Mods the top 2 items on the stack 1 byte
6 INOT Checks the first item on the stack to see if it equals 0 1 byte
7 INEG Reverses the sign on the item on the top of the stack 1 byte
8 IEQ Compares the top 2 integers on the stack to see if they are equal 1 byte
9 INE Compares the top 2 integers on the stack to see if they are not equal 1 byte
10 IGT Compares the top 2 integers on the stack to see if the first one is greater than the second one 1 byte
11 IGE Compares the top 2 integers on the stack to see if the first one is greater than or equal to the second one 1 byte
12 ILT Compares the top 2 integers on the stack to see if the first one is less than the second one 1 byte
13 ILE Compares the top 2 integers on the stack to see if the first one is less than or equal to the second one 1 byte
14 FADD Adds the top 2 floats on the stack 1 byte
15 FSUB Subtracts the top 2 floats on the stack 1 byte
16 FMUL Multiplies the top 2 floats on the stack 1 byte
17 FDIV Divides the top 2 floats on the stack 1 byte
18 FMOD Mods the top 2 floats on the stack 1 byte
19 FNEG Reverses the sign on the first float on the stack 1 byte
20 FEQ Compares the top 2 floats on the stack to see if they are equal 1 byte
21 FNE Compares the top 2 floats on the stack to see if they are not equal 1 byte
22 FGT Compares the top 2 floats on the stack to see if the first one is greater than the second one 1 byte
23 FGE Compares the top 2 floats on the stack to see if the first one is greater than or equal to the second one 1 byte
24 FLT Compares the top 2 floats on the stack to see if the first one is less than the second one 1 byte
25 FLE Compares the top 2 floats on the stack to see if the first one is less than or equal to the second one 1 byte
26 VADD Adds the top 2 Vectors[1] on the stack 1 byte
27 VSUB Subtracts the top 2 Vectors[1] on the stack 1 byte
28 VMUL Multiplies the top 2 Vectors[1] on the stack 1 byte
29 VDIV Divides the top 2 Vectors[1] on the stack 1 byte
30 VNEG Reverses the sign on the first vector[1] on the stack 1 byte
31 IAND Performs an And operation to the first 2 integers on the stack 1 byte
32 IOR Performs an Or operation to the first 2 integers on the stack 1 byte
33 IXOR Performs a Xor operation to the first 2 integers on the stack 1 byte
34 J Jumps to a section of code, using the next 4 bytes after the opcode as a placement 5 bytes
35 JZ Jumps to a section of code if the top of the stack is 0, using the next 4 bytes after the opcode as a placement 5 bytes
36 JNZ Jumps to a section of code if the top of the stack is 1, using the next 4 bytes after the opcode as a placement 5 bytes
37 I2F Converts the top integer on the stack to a float, and puts that float on the stack 1 byte
38 F2I Converts the top float on the stack to an integer, and puts that integer on the stack 1 byte
39 F2V Converts the top float into a Vector[1] containing 3 instances of the same float, and pushes the pointer to that Vector[1] onto the top of the stack 1 byte
40 PUSH_CONST_U16 Pushes a short onto the stack, the short is defined in the next 2 bytes after the opcode 3 bytes
41 PUSH_CONST_U32 Pushes an int onto the stack, the integer is defined in the next 4 bytes after the opcode 5 bytes
42 PUSH_CONST_F Pushes a float onto the stack, the float is defined in the next 4 bytes after the opcode. Performs exactly the same as Push 5 bytes
43 DUP Duplicates the first item on the stack, and pushes it back onto the stack 1 byte
44 DROP Pops the top item off the stack 1 byte
45 NATIVE Calls a native function. The number of arguments for the native to take is defined in the next byte after the opcode. The number of return values is defined in the byte after that (it is always 1 or 0). The next 4 bytes are the hash of the native's name. 7 bytes
46 CALL Calls a function within the script, and puts the return address on top of the stack. The location of the function is defined in the next 4 bytes after the opcode 5 bytes
47 ENTER Indicates the beginning of an internal function. The byte after the opcode indicates the amount of arguments the function takes off the stack, and the next 2 bytes after that indicate the number of variables the function will have to generate on the stack. 4 bytes
48 LEAVE Indicates the end of an internal function. The byte after the opcode indicates the amount of arguments that will have to be popped off the stack, and the next byte after that indicates the stack number of the return address 3 bytes
49 LOAD Pops a pointer off the stack and pushes the value stored in that pointer back onto the stack 1 byte
50 STORE Pops 2 items off the stack and stores the second item at the location of the first item (the first item being a pointer) 1 byte
51 STORE_REV Pops the first item off the stack and peeks at the second item on the stack, then stores the first item at the location pointed to by the second item on the stack 1 byte
52 ARRAY_LOAD Pops 2 items off the stack, the first and second items being the beginning of the memory of the array and the end of the memory of the array. It then divides the difference of these 2 locations by 4 to get the number of items in the array, after which is pushes these items one by one onto the stack in 4 byte segments 1 byte
53 ARRAY_STORE Pops the first item off the stack to get the address of the array to write to, and then pops the stack off onto that array 1 byte
54 LOCAL_0 Pushes the pointer to the first function local variable onto the stack. 1 byte
55 LOCAL_1 Pushes the pointer to the second function local variable onto the stack. 1 byte
56 LOCAL_2 Pushes the pointer to the third function local variable onto the stack. 1 byte
57 LOCAL_3 Pushes the pointer to the fourth function local variable onto the stack. 1 byte
58 LOCAL_4 Pushes the pointer to the fifth function local variable onto the stack. 1 byte
59 LOCAL_5 Pushes the pointer to the sixth function local variable onto the stack. 1 byte
60 LOCAL_6 Pushes the pointer to the seventh function local variable onto the stack. 1 byte
61 LOCAL_7 Pushes the pointer to the eigth function local variable onto the stack. 1 byte
62 LOCAL Pushes the pointer to a function local variable onto the stack where the index is above or equal to 8 1 byte
63 STATIC Pops the index of the static variable off the stack, and pushes a pointer to the script static variable onto the stack 1 byte
64 GLOBAL Pops the index of the global variable off the stack, and pushes a pointer to the public variable onto the stack 1 byte
65 ARRAY Pops the array location, element size and index off the stack, the pushes a pointer to the index of that array onto the stack 1 byte
66 SWITCH Pops the item to compare off the stack, and then jumps to location corresponding to that item. After the opcode byte it contains a byte defining the number of possible entries, and after that the number of possible entries times 8 are taken up with repeating instances of 4 bytes of the index identifier, and 4 bytes of the location to jump to if that index is correct (Byte after opcode * 8) + 2
67 STRING Pushes a string onto the stack. The byte after the opcode signals the string length, and for the amount of string length after that byte contains each character of the string (Byte after opcode)+2
68 NULL Pushes a pointer to an empty memory container onto the stack 1 byte
69 TEXT_LABEL_ASSIGN_STRING Pops 2 pointers off the stack, and copies the second item to the first item 1 byte
70 TEXT_LABEL_ASSIGN_INT Pops an integer off the stack and pushes an array to a string representation of that integer onto the stack 1 byte
71 TEXT_LABEL_APPEND_STRING Pops 2 pointers off the stack, and appends the second item to the first item 1 byte
72 TEXT_LABEL_APPEND_INT Pops 2 items off the stack, and performs a IntToStr on the second item (the integer), then appends that string representation to the first item 1 byte
73 CATCH Sets up a safe area that has the ability to catch errors 1 byte
74 THROW Indicates an area that handles a script error relative to the catch opcode 1 byte
75 TEXT_LABEL_COPY Pops 3 items off the stack. Copies the third item's memory into the first item's memory with repeating defined by the second item. It then appends a null terminator to the first item's memory 1 byte
76 getxprotect Pops a memory location off the stack and pushes its XLive unprotected value onto the stack (PC Only) 1 byte
77 setxprotect Pops a memory location off the stack, pops another value off the stack. Protects the second value using XLive and stores the value in the memory location. (PC Only) 1 byte
78 refxprotect Pops a memory location off the stack, pops another value off the stack to determine protection flags, and finally pops another value which indicates the number of items to operate on. If the 1st bit of the flags is set, the number of items at the memory location will be XLive unprotected. If the 2nd bit is set, they will be XLive protected instead. (PC Only) 1 byte
79 EXIT Terminates the script under an error condition 1 byte
80 -> 255 PUSH_CONST_U8 Pushes an integer onto the stack. The integer is defined by the opcode number - 96. For example opcode 95 would push -1 onto the stack, and opcode 97 would push 1 1 byte

^ The Vectors on the stack are pointers to the memory containing the full vector. A Vector is characterised by this structure:

4b - FLOAT32 - X
4b - FLOAT32 - Y
4b - FLOAT32 - Z

Static Variables

This contains the Static Variables in the script. Each static variable is 4 bytes long, and can contain static information in the script file itself.

Global Variables

It is uncertain what this section actually does.

High Level Representation

To turn the assembly of a SCO file into a high level representation some factors have to be considered. Arrays and structures can be defined, so it is reasonable to assume there is some kind of typecasting, even if it is only between the following types; int, float, string or a predefined structure. It is interesting to note that opcodes exist to typecast integers and concatenate them directly to strings, this suggests the SCO language has a java like way of handling strings (using + and += for concatenation). The SCO file does not seem to have native support for the notion of classes, however this is not to say they could not be implemented within SCO itself similar to how they are done at a low level in C++.

Tools

See also

External link