A Story
If you’ve used GameMaker for a bit, you might know what’s wrong with this.
instance_create_depth(omod_instance, 0, 0, 10)
The arguments are in the wrong order, but instead of providing a helpful error message, GameMaker accepts the arguments and keeps running. The reason why GameMaker doesn’t reject this function call is because omod_instance
is actually just a number. This is what GameMaker actually sees:
instance_create_depth(329, 0, 0, 10)
“Pointers”
If you’ve taken a low-level programming course or come from other game engines, then this probably isn’t too unexpected. Because of boring performance reasons, it’s better to use a single number than an entire string, at the cost of making things slightly more difficult.
Basically everything the game tracks is secretly just a number. This includes Game Objects, Instances, Sprites, Rooms, audio assets, shaders, constants (ie ev_create
, vk_home
, etc ), some GML language keywords (self
, all
, true
, etc), functions, data structures (buffers, ds_maps, etc), and probably more I haven’t run into yet.
Here’s a few common keywords and their internal numbers.
Keyword | Internal Value |
---|---|
true | 1 |
false | 0 |
self | -1 |
other | -2 |
all | -3 |
noone | -4 |
For most use cases, this information is irrelevant. However, if you’re using json_stringify
for serialization or debugging purposes, you should use json_encode
with GML data structures.
Undertale Mod Tool
When using Undertale Mod Tool, eventually you’ll run into code that looks like this.
// gml_Object_oplayer_Create_0
...
sprite_dead = 595
sprite_hit = 1369
hair_start_col = 3026478
hair_end_col = 6707256
hair_number = 3
hair_size = 2.5
hair_alt = -1
...
Despite all seven variables being initialized to numbers, their actual purpose varies dramatically. The first two, sprite_dead
and sprite_hit
, are referencing Sprite indexes for splayer_maya_dead
and splayer_maya_hit
respectively. hair_start_col
and hair_end_col
are hex code colors, 2E 2E 2E
and 66 58 38
in RGB. hair_alt
is -1
so it evaluates as false
for conditional statements, but is normally an array. hair_number
and hair_size
are the only two “normal” numbers here.
When using Undertale Mod Tool, you can right click on one of these weird numbers and get a list of possible assets it could be. If you’ve exported the code or are looking for references to a Game Object or Sprite, you might want a list of every internal identifier.
Identifier Dump Mod
The key technology here are the _get_name
functions, which take an identifier and return the name of the asset. Additionally, these identifiers are not stable. If possible, you should use the actual names of the asset, or find the index at runtime.
# controller
## create
```sp
global.ripper = {}
global.ripper.type = 2
global.ripper.saved_index = 0
global.ripper.max = 100
```
## step
```sp
let log = file_text_open_append("asset_list.txt")
let i = 0
while i < global.ripper.max {
let name
let next
let exists = false
match global.ripper.type {
case 0 {
name = sprite_get_name(global.ripper.saved_index)
exists = sprite_exists(global.ripper.saved_index)
next = "room"
}
case 1 {
name = room_get_name(global.ripper.saved_index)
exists = room_exists(global.ripper.saved_index)
next = "object"
}
case 2 {
name = object_get_name(global.ripper.saved_index)
exists = object_exists(global.ripper.saved_index)
next = "END"
}
case 4 {
file_text_close(log)
!"Done"
}
}
if !exists {
file_text_write_string(log, next + "\n")
global.ripper.saved_index = -1
global.ripper.type += 1
} else {
file_text_write_string(log, string(global.ripper.saved_index) + "\t:" + name + "\n")
}
i += 1
global.ripper.saved_index += 1
}
file_text_close(log)
```