Catspeak Reference


Catspeak For Developers

Catspeak is the spiritual successor to the old GML function execute_string. This means that custom user code can be executed as a string by your game for modding support or a debug console. In nerdspeak: Catspeak is a compiler backend and virtual machine for executing arbitrary code at runtime.

Unlike execute_string, Catspeak is slightly more involved, requiring three separate steps:

In order for your modders to access information about your game, you need to manually expose a modding API (covered briefly in the Interfacing with GML section). Catspeak does not do this for you by default. Further information about different methods to expose functions can be found in the Library Reference book.

If this busywork does not sound interesting to you, and you're the kind of developer who likes to cut corners, then you can throw caution to the wind and include the following code in your project:

Catspeak (.meow)
CopyCatspeak.interface.exposeEverythingIDontCareIfModdersCanEditUsersSaveFilesJustLetMeDoThis = true;

This will force Catspeak lift the veil safety and attempt to give modders access every intimate detail about your game. Don't say I didn't warn you.

§ Parsingtop ^

Parsing is the first step. This involves taking the human-readable form of Catspeak source code, and converting it into an executable form. This can be done from a string or a UTF-8 encoded buffer.

Parsing code from a string using Catspeak.parseString:

GameMaker Language (.gml)
Copyvar hir = Catspeak.parseString(@' let n = 0 while n <= 10 { n += 1 } return "blast off!" ');

Parsing code from a file called "my_mod.meow", using Catspeak.parse:

GameMaker Language (.gml)
Copyvar file = buffer_load("my_mod.meow"); var hir = Catspeak.parse(file); buffer_delete(file);

The parser produces a hierarchical intermediate-representation (HIR), storing information like what functions are defined, where they are defined, how many variables are used, what functions are being called and when, etc.

This information is stored as a JSON object, so you can cache this to a file to avoid parsing large mods every time the game loads.

§ Compilingtop ^

Compiling is the second step. This involves taking the executable form of a Catspeak program (the HIR obtained from Parsing) and transforms it into a callable GML function.

Compiling a program from the hir using Catspeak.compile:

GameMaker Language (.gml)
Copyvar program = Catspeak.compile(hir);

§ Executingtop ^

Executing is the third and final step; this is the fun part. After compiling a program, it can be called like any ordinary GML function like:

GameMaker Language (.gml)
Copyprogram();

As many times as you want:

GameMaker Language (.gml)
Copyprogram(); program(); program(); repeat (10) { program(); }

When adding mod support, you should aim to pre-compile all of your mod scripts at the start of the game, and then reuse the compiled program during gameplay. Otherwise, your game may experience performance issues due to the slowness of parsing and compiling programs relative to execution.

§ Interfacing with GMLtop ^

You can expose additional functions, constants, and assets to Catspeak programs by using the methods on Catspeak.interface. For example, using the functions exposeFunction, exposeConstant, and exposeAsset to make show_message, pi, and spr_player available from within a Catspeak function:

GameMaker Language (.gml)
CopyCatspeak.interface.exposeFunction("show_message", show_message); Catspeak.interface.exposeConstant("math_pi", pi); Catspeak.interface.exposeAsset("sPlayer", spr_player);

Then using these from within a custom Catspeak function, like:

GameMaker Language (.gml)
Copyvar hir = Catspeak.parseString(@' let tau = math_pi * 2; show_message([sPlayer, tau]); '); var program = Catspeak.compile(hir); program();

This is necessary so that modders are sandboxed from each other, and don't have unchecked access to your entire game state. There are many other ways of exposing GML assets to Catspeak programs, see CatspeakForeignInterface