Hot Reload - coldrockgames/gml-raptor GitHub Wiki

Debugging your game can be an extremely time consuming thing. Especially when your game grows and it takes some time to reach the point in the game where things go wrong.

With the implementation of the Scriptor Scripting Language and the super powerful RichJson System, raptor has evolved to a level that disconnects your game logic from the render logic (the gml code). Done right, you will place most of your enemies, fights, dungeons in scriptor files and initialize them through RichJson to give them the skins and connect the game events.

This means, many things that can go wrong in your game will be placed outside of the GameMaker project, in json files and scriptor scripts.

With classic coding you are forced to restart your game, edit bugs, start again, reach the critical point, try again, and restart until it is fixed. With Raptor you can simply reload your game logic while the game is running. If you want you can restart the room and try again without having to quit the game!

The RaptorHotReloadManager Class

There is always one instance of this class active while the game runs in CONFIGURATION_DEV (i.e. the "Default" configuration or any config derived from it). In Beta and Release modes, hot reloading is disabled, as all external assets are encrypted by raptor and can't be modified.

Pressing F12 while your game runs, opens the debug views.

They now offer a Hot Reload Panel. From the Demo Program, where this screenshot has been taken, only the Scriptor hot-reload module was active, but this panel will automatically offer you all registered modules capable of doing a hot-reload.

If you click the button, all scripts get reloaded, recompiled and can be launched without interrupting the game! The RaptorHotReloadManager handles the process for you.

The RaptorHotReloadModule Class

You can create your own hot-reload modules if you have resources in your game, that may make sense to be reloaded while running.

The process is fairly simple:

RAPTOR_HOT_RELOAD_MANAGER.register_module(new RaptorHotReloadModule("your-module-name")
	.set_on_prepare(function() {
		// Return true or false here
		// telling the system whether you could
		// initialize successfully or not
	})
	.set_on_execute(function() {
		// Execute your hot-reload (see below)
	})
	.set_on_disable(function() {
		// Clean up your resources or scripts
	})
);
  • You just call the RAPTOR_HOT_RELOAD_MANAGER and register your module.
  • "Execute your hot-reload" will very likely be a Shell Execute call which copies your modified scripts to the running VM.
  • In the disable function you may delete your temporary script.

Create Your Copy Script

Raptor supports you here through its build script pre_project_step.bat. This script generates a temporary json file when you compile your game. This json file contains the source code location (the current folder of your yyp project) and is picked up from the GameStarter object of raptor.

There is a constant/macro available in the game, RAPTOR_HOT_RELOAD_SOURCE, which contains exactly this folder. You can use this constant to create a temporary copy script which transfers your files to the VM.

Less theory, more action! As an example, here is the gml-code from the Scriptor module which copies all scripts to the running VM:

file_write_text_file(__SCRIPTOR_HOT_RELOAD_SCRIPT_NAME, string_join("\r\n",
	"@ECHO OFF",
	$"XCOPY {RAPTOR_HOT_RELOAD_SOURCE}\\datafiles\\{SCRIPTOR_ROOT_FOLDER}\\*.* {working_directory}{SCRIPTOR_ROOT_FOLDER} /E /Y",
));

This script gets executed in the on_execute function of the module and copies all script files to the VM. Shell Execute offers a callback when the copying is done, and in this callback the module just tells scriptor to compile all scripts. Et voilà! Everything is updated!

Here (a bit shortened to fit better on the page) the execute method, how this script is run:

shell_run_wait($"call \"{game_save_id}{__SCRIPTOR_HOT_RELOAD_SCRIPT_NAME}\"",
    function(_data) { // <-- this is the finished_callback when the script is done.
        SCRIPTOR_SCRIPTS = {};
        SCRIPTOR_BROKER.clear();

        // this function reads and recompiles all scripts
        scriptor_read_script_tree_async(
            function(_data, _modname) { 
                // Tell the manager to close the progress window
                RAPTOR_HOT_RELOAD_MANAGER.hotreload_finished(_modname);
        );
    }
);