Getting started

Limits and errors

Time and memory limits, and what happens when a plugin fails.

Each plugin has its own limits, so one plugin can't slow the game down or starve the others. Time is counted in Lua instructions.

task_budget
Instructions all of a plugin's tasks may run each tick (2 million by default). A task that goes over just pauses and continues next tick.
frame_budget
Instructions all of a plugin's callbacks may run each tick (40 million by default). Past it, that tick's remaining callbacks are skipped, with a warning in the console.
callback_budget
Instructions a single callback may run (20 million by default). A callback that goes over stops the plugin with an error.
memory_limit_mb
Memory the plugin may use (64 MB by default). Going over is an ordinary Lua error, not enough memory, which pcall can catch.

The limits are set once for every Lua plugin, in the Lua Plugins host's own config file, config/lua-plugin.json in the injector's config folder. A plugin's own settings file (config/lua-<plugin>.json) doesn't hold them.

Long library calls

A single library call that calls back into Lua, like table.sort with a comparison function or string.gsub with a replacement function, can't be paused part way. One that runs far past the budget stops the plugin; split such work into smaller pieces.

Errors

An error nothing catches stops the plugin. It shows in the console with the file, line and a traceback, and the plugin's row turns red. on_stop("error") still runs. Fix the file and press reload.

Wrap code that may fail in pcall to handle the error yourself:

local ok, err = pcall(function()
    -- something that may fail
end)
if not ok then warn("failed: " .. tostring(err)) end

Safe UI

Every ui.begin_* and ui.push_* needs its ui.end_* or ui.pop_*. An end_* that doesn't match is a Lua error rather than a crash, and anything still open when on_render returns (or fails) is closed for you, with a warning. A script error can't take the game's interface down with it.