Bytecode version differences - UnderminersTeam/UndertaleModTool GitHub Wiki

v15 vs v16

TODO: test if these are actually bytecode related, or just a newer version of GMS runtime (like with the padding or GMS2 stuff)

v15 v16
No LANG chunk Contains a new LANG chunk
No ROOM.GameObject.PreCreate Contains a new ID reference to a Pre-Create code entry

These two changes is literally all I could see. Let me know if you can find anything else.

v14 vs v15

To begin, here are the major file format updates between the two.

v14 v15
No code local information The end of the FUNC chunk has code locals
VARI chunk does not have initial 3 integers, variables do not have InstanceType or ID VARI chunk has initial 3 integers (InstanceVarCount, InstanceVarCountAgain, MaxLocalVarCount), variables have InstanceType and ID
FUNC chunk is only an array with NO length, containing function information FUNC chunk has an array WITH length, containing function information, followed by an array (with length) containing code local information
Each code entry has a string pointer to its name, followed by int32 length, immediately followed by the bytecode (using length) Each code entry has a string pointer to its name, followed by int32 length, followed by int32 code local count, followed by int32 bytecode relative address, followed by int32 offset within the bytecode

Additionally, from bytecode 14 to 15, the entire instruction set was changed. Here's a list of the basic operation opcode changes, with their patterns

Name v14 Opcode v15 Opcode
(Pattern for operations) v15 opcode - 0x04 v14 opcode + 0x04
Conv 0x03 0x07
Mul 0x04 0x08
Div 0x05 0x09
Rem 0x06 0x0A
Mod 0x07 0x0B
Add 0x08 0x0C
Sub 0x09 0x0D
And 0x0A 0x0E
Or 0x0B 0x0F
Xor 0x0C 0x10
Neg 0x0D 0x11
Not 0x0E 0x12
Shl (shift left) 0x0F 0x13
Shr (shift right) 0x10 0x14
Pop 0x41 0x45
Dup 0x82 0x86
(Pattern for most others) v15 opcode + 0x01 v14 opcode - 0x01
Ret 0x9D 0x9C
Exit 0x9E 0x9D
Popz 0x9F 0x9E
B 0xB7 0xB6
Bt 0xB8 0xB7
Bf 0xB9 0xB8
PushEnv 0xBB 0xBA
PopEnv 0xBC 0xBB
Call 0xDA 0xD9
(Exceptions)
Cmp (not in v14 as one) 0x11 to 0x16 0x15
Cmp (<) 0x11 N/A
Cmp (<=) 0x12 N/A
Cmp (==) 0x13 N/A
Cmp (!=) 0x14 N/A
Cmp (>=) 0x15 N/A
Cmp (>) 0x16 N/A
Push 0xC0 0xC0
PushLoc N/A 0xC1
PushGlb N/A 0xC2
PushVar (builtin) N/A 0xC3
PushI (int16) N/A 0x84
Break (unchanged) 0xFF 0xFF

In this list are some major exceptions - the Cmp instruction(s) and Push instruction(s).

For the Cmp instructions in bytecode 14, the ComparisonType parameter is unused (zero), and the opcode takes its place. Conveniently, they are in the same order as ComparisonType.

For the Push instruction in bytecode 14, it obviously only has one opcode instead of bytecode 15's five. This means that it depends on the instruction's data type heavily. To put it simply, if the data type is Variable, then the first two bytes of the instruction have the variable scope as an int16, be it -5 (global, PushGlb), -6 (builtin, PushVar), or -7 (local, PushLoc). Other types such as -1 (self) also exist, but is unnecessary because it already assumes them. Also, if the data type is Int16, then the instruction is the equivalent of bytecode 15's PushI. As a side note, this means that instructions like push.e and pushi.e are now equivalent.

One other final note is that exiting a with statement early produces a PopEnv with a magic number (in both versions), and in the case of bytecode 14, it seemingly produces 00 00 F0 BC.

v13 vs v14

TODO: test if these are actually bytecode related, or just a newer version of GMS runtime (like with the padding or GMS2 stuff)

v13 v14
No AGRP chunk Contains a new AGRP chunk
No debugger port Has a debugger port in GEN8
Different font padding Consistent font padding

It's also worth noting that some version within bytecode 13 changed the OPTN chunk drastically. Previously there were numerous 32-bit booleans for options, and these became a single 64-bit bitflag.