Workflow and User Events - Grisgram/gml-raptor GitHub Wiki

I've tried to simplify the workflow for the complicated task of creating a savegame file as much as possible, and I ended up with only two user events that might need attention while the game is saved or loaded.

In addition to that, some objects might need to know when they are created, whether it is a regular object spawn or if the instance was just created during the game load workflow.
An example for this could be an object that creates additional child instances when it is created (like preparing some bullets so it can shoot or some animated objects surrounding it). If the object just gets restored from a save game, it does not need to create those children since they have to be part of the savegame anyway (like mentioned in Planning your Savegame) and will get created by the Savegame system.
This is the moment, where you might want to query the SAVEGAME_LOAD_IN_PROGRESS or SAVEGAME_SAVE_IN_PROGRESS macros to skip that part in this case.

The next logical question is, "Ok, but when those child objects are also created for me, how can the Savegame know that these 25 Bullets are my Bullets? What about the links between objects, restoring pointers to other instances?".
Savegame does that!
But before I go into detail, let's look at the timing in the workflow, especially the two *_IN_PROGRESS macros mentioned above. You need to know when they are true or false to understand how instance link save and restore works.

Saving Loading
SAVEGAME_SAVE_IN_PROGRESS = true SAVEGAME_LOAD_IN_PROGRESS = true
onGameSaving (User Event 14) onGameLoading (function)
onGameSaving (function) SAVEGAME_LOAD_IN_PROGRESS = false
SAVEGAME_SAVE_IN_PROGRESS = false onGameLoaded (User Event 15)
onGameSaved (function) onGameLoaded (function)

You can see, the present participle ...ing (Sav_ing, Load_ing) functions are invoked while the progress variables are true and the past tense ...ed functions are invoked after the flags return to false. So, from a timing view, after the process has completed, but before the control is given back to the game. From the call stack perspective, we are still in the save or load function respectively.

Saving and restoring instance connections

GameMaker assigns each object a unique id when it gets created. This will very likely not be the same when the game is loaded back into memory and the objects are created. So we need some kind of reference that allows us to "re-link" objects after they have been loaded.

When saving, Savegame detects all instance_ids in the structs to be saved.
Instead of blindly serializing object-in-object-in-object to the savegame, those instances are replaced by special markers in the file.
They look like "objref" : "##_savegame_ref_##.100006".

When the game is loaded, Savegame builds a reference table, containing the "old id" (the number 100006 in the example above) and the "new id", which is the instance id from the object after instance_create_layer or instance_create_depth has been invoked by Savegame and the new instance has been created.

This process is repeated until all objects are created.
It then loops over all created objects and replaces the marker with the instance of the new object to restore the link.

An example for the use of SAVEGAME_LOAD_IN_PROGRESS

This code example shows how you can avoid creating unnecessary objects when the game is loaded and child objects will be created by the Savegame engine.

// Create event

// Note: this is held in data!
// The objects `Bullet` and `AnimatedShield` are assumed to be also a Saveable objects!
data.my_bullets = array_create(25);
data.my_orbiting_shield = undefined;

// Take care, to create bullets only, if you are not currently restored from a savegame
if (!SAVEGAME_LOAD_IN_PROGRESS) {
    var i = 0; repeat(array_length(data.my_bullets)) {
        data.my_bullets[@ i] = instance_create_layer(x, y, "Instances", Bullet);
        i++;
    }

    data.my_orbiting_shield = instance_create_layer(x, y, "Instances", AnimatedShield);
}

Next, you should read, how the Savegame System invokes constructors of your script classes when loading the game. Find it out in Invoking Constructors.

⚠️ **GitHub.com Fallback** ⚠️