This is a "cheat sheet" for GMLive.gml extension by YellowAfterlife.
The extension can be acquired from GM:Marketplace or itch.io.
For questions/support, use forums, or send me an email.
An up-to-date version of this document can always be found online.

Click on sections to expand/collapse them.
Quick display controls: Categories · Sections · Everything ·

Using GMLive.gml in GMS1

Initial setup

Setting up is as following:

  • Make sure that you are running an up-to-date version of GameMaker: Studio.
    You can find links to all versions at official website.
  • Import the GMLive extension to the project.
    With GMEZ file, either right-click on "Extensions" category in project tree and pick "import extension", or just drag-and-drop the file onto IDE from Explorer.
  • Import the assets (included files and obj_gmlive) from the package.
    To do so, right-click on the extension, pick "Properties", and use the "Import" tab.
    Depending on factors, it can take GMS1 a bit of time to show the dialog.
    If it's stuck for good, use 7-zip (or equivalent) to unpack the GMEZ file, and import the assets (contents of "datafiles" directory and obj_gmlive.object.gmx) via dragging and dropping them onto IDE.
  • Place obj_gmlive in the first room of the project.
  • Open menu "Resources - Define Macros" (Ctrl+Shift+N) and add a macro called live_enabled with value 1.

Now, as you might know, GMS1 does not let you save project while the game is running on most targets. This can be solved in multiple ways:

A. Use netlog and GMLiveHelper extensions (when on Windows):

  • Right-click on netlog.gmez in Included Files and pick "Open in Explorer".
  • Import netlog.gmez and GMLiveHelper.gmez to the project (much like above).
  • When starting up gmlive-server, also run netlog.exe in Included Files.
  • Use netlog script for debug logging instead of show_debug_message.
    (which will display text in netlog's window when connected or IDE when not)

B. Compile and run the game instead of running it from IDE directly.

C. Use an external editor for changing the "live" files mid-game:

  • There's a free and open-source GM code editor I made that works well for this (among other things).
    There's also a decent number of plugins for GML support in existing editors (Notepad++, Sublime Text, Visual Studio Code, etc.).
  • This can be faster than other options because an external editor will only re-save the file in question while saving the project in GMS1 always also re-saves the .project.gmx (and makes a backup if you didn't disable "backup on save" in File - Preferences).
  • The file(s) in question should not be open in GM:S while you are editing them externally, or GMS1 might overwrite them with additional version next time you save the project. If accidents happen, copy the updated code from external editor back to GM:S. Enabling built-in version control for the projct reduces the chances of this happening.

Once you are done setting things up, you can remove netlog.gmez and GMLiveHelper.gmez from Included Files.

If you have Neko VM installed, you can also remove all DLL and NDLL files.

If you are not using option A, you can also remove netlog.exe and remove the live_restart_if_necessary line from obj_gmlive's Create event.

(you can always re-import the included files later on)

Starting up
  • Double-click gmlive-server.exe in Included Files to run it.
    You can leave it running when recompiling the game - it will re-scan the project directory whenever a new game instance connects to it.
  • If you've installed GMLiveHelper, also double-click netlog.exe.
    Similarly, can be left running between game sessions.
  • Add live function calls to scripts and events of interest.
    Note that for events the live-call must be in the first block of the event (since GMS simply combines them during compilation), and there may not be non-"Execute code" DnD blocks in the event.
  • Run the game.
  • Change the "live" scripts/events as you see fit and see the changes in-game (if everything was done correctly). gmlive-server' window will report status updates.
Exporting

Usually you do not want non-development builds of the game to periodically ping a local or non-local address - while not exactly resource-intensive, this may raise warnings on some firewalls and anti-virus software.

For that reason it is suggested that you disable GMLive prior to exporting.

To do so, open menu "Resources - Define Macros" (Ctrl+Shift+N), and change the value of previously defined live_enabled macro to 0.

This will disable the logic inside all of GMLive's scripts and return default values, having it that nothing will happen when calling them, and that they will not influence compile times/output size much as such.

After exporting you can set live_enabled back to 1.

Using GMLive.gml in GMS2

Initial setup
  • Import the GMLive asset the project.
    (with itch.io, you need to drag the .yymp file onto the workspace area)
  • Import the assets (extension, object, and included files) from the package.
    On Mac, omit importing Windows-specific exe and ndll files.
  • Place obj_gmlive in the first room of the project.
Starting up
  • Right-click gmlive-server.exe in Included Files, pick "Open in Explorer"
    (likely named "Open in Finder" on Mac)
  • On Windows, double-click the gmlive-server executable.
    On Mac, open Terminal in the directory and do neko gmlive-server.n (see gmlive-server for more information).
    You can leave it running when recompiling the game - it will re-scan the project directory whenever a new game instance connects to it.
  • Add live function calls to scripts and events of interest.
    Note that for events the live-call must be in the first block of the event (since GMS simply combines them during compilation), and there may not be non-"Execute code" DnD blocks in the event.
  • Run the game.
  • Change the "live" scripts/events as you see fit and see the changes in-game (if everything was done correctly). gmlive-server' window will report status updates.
Exporting

Usually you do not want non-development builds of the game to periodically ping a local or non-local address - while not exactly resource-intensive, this may raise warnings on some firewalls and anti-virus software.

For that reason it is suggested that you disable GMLive prior to exporting.

To do so, change the value of live_enabled macro in obj_gmlive's Create event to 0.

This will disable the logic inside all of GMLive's scripts and return default values, having it that nothing will happen when calling them, and that they will not influence compile times/output size much as such.

After exporting you can set live_enabled back to 1.

General functions

live_init(update_rate, url, password)

update_rate is how often files should be checked for updates, in seconds. 1 is a common value. Lower values can load changed files faster, but will also cause file system to be polled more frequently.

url is the URL that gmlive-server is running on. Most often you would have this as "http://127.0.0.1:5100" to connect to the server on the same machine.

password is the password set via gmlive-server' --password option, as a basic form of security if running the server in an unprotected network. If you did not specify one, this should be left as a blank string.

live_log_script

Can be assigned to a script that GMLive will call to display debug information (such as notifications about scripts being reloaded), e.g.

live_log_script = scr_log;

If not assigned, plain show_debug_message calls are used.

live_execute_string(gml_code)

Attempts to compile and run a snippet of GML code.

Returns whether execution succeeded. If it did, live_result contains the returned value (if any). If it didn't, live_result contains the error text.

if (live_execute_string(@'show_message("Hello!"); return 1')) {
	show_debug_message("Result: " + string(live_result));
} else show_debug_message("Error: " + string(live_result));

Please keep in mind that much like the similarly-named GM<=8.1 function, this compiles code on every call, thus is not fast and should only be used for debugging (e.g. if you want to be able to type snippets of GML in-game for quick tests).

Live functions

live_call(...arguments)

Calls the "live" version of the current script/event with specified arguments (if any).

Returns whether the "live" version is already loaded and was called.

If execution succeeds, live_result contains the returned value.

If execution fails, live_result contains 0 (also see live_defcall).

For example, if your script takes no arguments, you could do:

/// scr_test
if (live_call()) return live_result;
return "Hello!";

If your script takes two arguments, you could do:

/// scr_add(a, b)
if (live_call(argument0, argument1)) return live_result;
return argument0 + argument1;

If your script takes a varying number of arguments, see live_call_ext.

live_call_ext(argument_array)

Same as live_call, but allows to pass arguments as an array instead of a fixed list. You would usually use it like the following:

var argument_arr = array_create(argument_count);
for (var i = 0; i < argument_count; i++) {
	argument_arr[i] = argument[i];
}
if (live_call_ext(argument_arr)) return live_result;

(unfortunately, GM macros do not currently allow to use argument[] / argument_count inside of them, but you can add the code as a "snippet" in GM)

live_defcall(...arguments, default_value)

Same as live_call but returns default_value instead of 0 if execution fails.

This is handy if livecoding a script that may only return values of specific type (thus specifying a default value would allow to avoid errors outside of "live" code).

For example,

/// scr_transform_string(string)
if (live_defcall(argument0, "")) return live_result;
// (some risky manipulations with string)

would return "" if execution of the "live" code fails.

live_defcall_ext(argument_array, default_value)

A mix of live_call_ext and live_defcall - you can both pass arguments as an array and a default return value.

live_result

Stores the returned value from the last live_call (or other "live" group functions) if execution succeeded. If the code did not return anything, holds 0 (GM default for exit).

Sprite functions

sprite_set_live(sprite, enable)

Enables/disables live reload for a specific sprite.

Does not work for Spine/SWF sprites (as they cannot be reloaded at runtime).

For example,

sprite_set_live(spr_test, true);

Can be called at runtime, including from "live" code.

While it might be tempting to call this for all the sprites, usually you should not, as the server has to watch "live" sprites and their subimages for changes, and this can add up in disk access time on larger projects.

Room functions

Setting up
  • Create an empty object and name it, for example, obj_blank;
  • Create an empty room and name it, for example, rm_blank;
    If using GMS2, remove the default instance and background layers;
    Add the following to it's Room Creation Code:

    live_room_start();
    

  • Assign the two to live_blank_object and live_blank_room in obj_gmlive's Create event:

    live_blank_object = obj_blank;
    live_blank_room = rm_blank;
    

room_set_live(room, enable)

Enables/disables live reload for a specific room. Don't forget to setup helper resources first.

For example,

room_set_live(rm_test, true);

Can be called at runtime, including from "live" code.

room_goto_live(room)

Transits to the specified room much like regular room_goto.

If a "live" version of the room is loaded, transits to live_blank_room instead and loads the new version of the room there.

live_room_updated

If set, this script will be called whenever a new version of a room is received.

So you could, for example, do

live_room_updated = scr_room_updated;

and then have that scr_room_updated do

/// scr_room_updated(rm)
room_goto_live(argument0);
Limitations

Referencing "live" instances by name from non-"live" code

Since instance names are transformed into hardcoded instance IDs during compilation, this will not work.
Consider assigning instances of interest into global variables in room creation code if you need to - that way you'll assign IDs that were given out to "live" versions as the "live" code would know the "new" ones.

(anything else?)

This feature is relatively new and the topic of room loading is relatively complex so it is possible that you'll encounter some issues that I've not even thought of testing for. Make sure to report things that break.

Technical topics

gmlive-server

Is a helper application for GMLive.gml. It does a few things:

  • Fetches resources from the project.
  • Watches "live" files for changes.
  • Sends updated files to the game.

Starting up without arguments (such as by double-clicking the executable) has it automatically pick the GMS1/GMS2 project in the parent directory.

Passing an argument (such as by dragging a file/directory onto the executable) has it load up the specified project.

Starting up from command-line/PowerShell/terminal allows to specify additional arguments:

  • --port <port number>: Sets a custom port to run the server on.
    You shouldn't need to touch this unless the default port (5100) is being used by some other application or you desire to run multiple gmlive-server instances on multiple project directories at once.
  • --password <string>: Sets a custom password (to be passed in live_init).
  • --timeout <seconds>: Adjusts connection timeout for clients.
    In other words, how long it is without a response before a connection is dropped and related data structures are cleaned up. Default is 60 seconds and you wouldn't usually need to touch this unless you have issues with the game disconnecting during a step-by-step debug session.

On the technical side, gmlive-server is a Neko VM application. For Windows, the few DLLs it uses and an executable version are packaged together with it. On Mac, you'll need to install Neko VM binaries (~1.5MB) to be able to run it from terminal via

neko gmlive-server.n
Error handling

Things that GMLive takes care of:

  • Syntax errors in "live" code
    (code will not be updated if the new version doesn't compile)
  • Value errors (e.g. trying to add a string to a number, dividing by 0)
  • Missing variables/instances
  • Wrong argument types passed to common built-in functions

When a "runtime" error occurs, it is logged and the "live" script/event halts execution. This does not prevent subsequent attempts to execute the code.

Things that GMLive cannot take care of:

  • Runtime errors in non-"live" scripts
  • Errors thrown by built-in functions (e.g. drawing nonexistent sprites)

Limitations

Performance

On average, any time you add another layer on interpreted code, performance degrades 5x..10x - YYC code is on average 5 times slower than equivalent handwritten C++ code, non-YYC GML is about 3..5 times slower than that, and GMLive, having runtime compiled to GML, has roughly GM8.1 level of performance on non-YYC and roughly regular GMS level of performance on YYC.

This has a few implications:

  • Enabling livecoding for too many performance-critical scripts at once isn't a good idea (although can be used to test and compare algorithms in realtime).
  • Using GMLive for ad-hoc modding support isn't a good idea - both for performance reasons and because the interpreted scripts would have complete access to GM API and game's resources.

That said, both GMLive and GameMaker are being worked on, thus things will likely improve as time goes on.

Calling functions in native extensions

GMLive by default has entirety of standard GameMaker API and all game-specific resources exposed to it, but native extension' functions currently cannot be dynamically referenced, therefore you would not be able to call them from "live" code by default.

As a workaround, you can make a script that calls the function, and then call that script (this is also what GMLive does for built-in GM functions).

Copy-on-write behaviour in arrays

GML itself has a particular feature (see "Advanced Array Functionality") that has it that passing an array as an argument to a script and then changing it via arr[index] = value rather than arr[@index] = value would clone the array prior.

The internal data for this is not exposed, however, so GMLive is unable to do it in the same way, and only does "create-on-write" (replacing a value with a new array if it isn't yet).

If this doesn't make immediate sense, it is unlikely that you rely on this feature anywhere.

Dynamic expressions in switch-cases

GML itself allows to put dynamic expressions into switch' cases, meaning that you could do

switch (global.a) {
	case global.b: return "a == b";
	case global.c: return "a == c";
	default: return "etc";
}

and it would be compiled to an equivalent of

var temp = global.a;
if (temp == global.b) {
	return "a == b";
} else if (temp == global.c) {
	return "a == c";
} else return "etc";

Needless to say, that does get a little nastier with fall-through cases, and GMLive currently may not agree to compile a "case" if it's expression cannot be computed compile-time (things like ord("A") are fine though).

Unusual expressions in macros

GML itself, for what can be considered interesting reasons, allows to put pretty much anything into a macro, except for the argument variables.

This means that you can technically have a macro called ohno with value 1 return "oh no", and do

var r = ohno;
return "ok";

and that would actually return "oh no" from the script while looking like a regular variable assignment.

GMS2 further expands on macro support, allowing to put entire blocks of code inside of a macros if you much desire.

GMLive currently sticks with "pure" macros, meaning that you can only put things that could have been put as a function argument in them (in other words, "values" / "expressions", rather than complete or partial "statements").

If you have "unusual" macros in the project, GMLive will still work, but you will not be able to use them in "live" code.

Troubleshooting

Code does not update
  • Make sure that you are saving the file (Ctrl+S).
  • Make sure that gmlive-server is running.
  • Check the output log for any compile/runtime errors with new code.
  • Check gmlive-server window for any project load errors.
  • Check if the time next to the client in gmlive-server window is ticking.
    If it's not ticking, you likely accidentally deactivated/destroyed obj_gmlive.
"Argument index is out of range"

This usually happens for one of two reasons:

  • You are calling the script with fewer arguments than you have the code expect
    (in which case GM would throw you an error as well).
  • You forgot to add script arguments to live_call/live_call_ext.
"Can't call instance-specific function - instance does not exist."

You can occsaionally get this error in output log when calling scripts for instances after deactivating/destroing them - currently the only way self/other instances can be set up for a call is via with blocks, and these do not work with deactivated/destroyed instance IDs.

GMLive uses a few workarounds to get around this in common situations (applying to original self/other instances of the event), but if you have something like

with (some_instance_id) {
	instance_destroy();
	scr_some_instance_script();
}

that may show that error.

As a workaround, you can either change your code not to attempt to call scripts on freshly deactivated/destroyed instances, or move the D/D+call branch into a separate script.

"Failed to load library : no suitable image found. "

You can get this on Mac if you did not remove original ndll files - NDLLs that Windows uses are different from those for OSX.