Catspeak and Code Execution - Skirlez/nubbys-forgery GitHub Wiki
Mods include Catspeak files. Catspeak, like GML, is a scripting language.
The modloader reads the Catspeak files that mods have, and executes them. If you know how to use GML, then Catspeak is very similar. This page goes over implementation details specific to the modloader. For a language overview see this page: https://www.katsaii.com/catspeak-lang/3.3.0/lan-overview.html
Nearly everything is exposed to you
Every single resource is exposed to you when running mods, except select functions. Here's a table with reasons as to why:
Functions | Reason |
---|---|
keyboard_key_press , keyboard_key_release |
High malicious potential, as these press keys out of the game too |
get_open_filename , get_save_filename , get_open_filename_ext , get_save_filename_ext |
These functions can bypass the save/load sandbox |
Important! Global built-in variables, such as room
, async_load
, view_camera
, etc. Can be obtained by adding _get()
to the end of their name. So to get the current room, you'd call room_get()
for example.
Executing your own code files
The modloader provides you with several functions to execute any code files belonging to your mod.
Let's say we have this file, at (your mod's folder)/folder/code.meow
:
log_info("Hello World!")
my_function = fun {
log_info("This is my function!")
}
We'll be using it as an example here.
mod_execute_code_file(path)
The simplest thing you can do is execute one of your code files, and that is what mod_execute_code_file(path)
does.
-- Get and run code file
mod_execute_code_file("folder/code.meow") -- logs "Hello World!"
mod_get_code_file(path)
You can use mod_get_code_file(path)
gets the code file at path
that belongs to this mod.
This is a relative path, meaning it starts from the mod folder.
After you get the file, you can run it like a function.
-- Get the file
file = mod_get_code_file("folder/code.meow")
-- Run it
file() -- logs "Hello World!"
catspeak_globals(code_file)
But say you want to access a function defined inside your code file. You need to access the file's global struct after it runs.
This can be done like so, with Catspeak's own catspeak_globals
function:
-- Get the file
file = mod_get_code_file("folder/code.meow")
-- Run it so the functions get defined, if you haven't ran it before
file() -- logs "Hello World!"
-- Get file globals
file_globals = catspeak_globals(file)
-- Call our function from the globals
file_globals.my_function() -- logs "This is my function!"
Important! You have to run the file before calling the function because the functions are not defined up to that point.
It is only when you run the file, and the line my_function = fun {
is reached, that the function exists.
You can think of running a code file as initializing it.
mod_get_code_file_globals(path)
You can use mod_get_code_file_globals(path)
, which returns the globals of a file right away.
file_globals = mod_get_code_file_globals("folder/code.meow") -- logs "Hello World!"
file_globals.my_function() -- logs "This is my function!"
Important! In order to do this, mod_get_code_file_globals
runs the file if its global struct is empty, i.e., it hasn't been run yet.
This is why the first line logs "Hello World!" - subsequent calls will not.
mod_get_code_file_globals("folder/code.meow") -- logs "Hello World!"
mod_get_code_file_globals("folder/code.meow") -- does not log
mod_get_code_file_globals("folder/code.meow") -- does not log
A note on performance
When you get a file using any of these functions, it is read and compiled in real-time once, and then cached. Any retrieval after that does not read the file from disk or compile anything. It's essentially as costly as a few hashmap accesses (So almost none at all)
Additionally, you may set compile_all_code_on_load
to true
in your mod.json
. This will cause all files to be read and compiled when the mod is loaded, so none of those functions will ever read from disk or compile. It will also prevent your mod from loading if any of your files fail to compile.