ss is the global every mod receives. It holds the whole API: the logging and handler functions below, the timers and signals, and the object classes listed under Classes. Each mod with a Scripts\main.lua gets its own Lua state (LuaJIT 2.1, which is Lua 5.1 with LuaJIT's extensions, jit and ffi included), and nothing is shared between mods: globals, require results and errors stay inside the mod that made them.

Functions#

Logging#

FunctionReturn ValuesDescription
ss.log(vararg values) nil Writes a line to the log. If the first value is a string and more values follow, the line is the result of string.format(...); otherwise each value is converted with tostring.
print(vararg values) nil The standard print, redirected to the same log.

Lines appear as sshook: lua: [<mod>] ... wherever the hook's own lines go: OutputDebugStringA on Windows, which DebugView shows, and the runtime's log file on the translated builds. See Reading the log.

Handlers#

A handler is a function registered for an event. Every handler receives a single table, ev, with the event's fields. Handlers run on the game's main thread, from the frame tick or from the hooked game function that raised the event, so a slow handler stalls the game for that long.

FunctionReturn ValuesDescription
ss.on( string event, function handler ) handler id Registers handler for the given event and returns an id for ss.off. Any number of handlers can listen to one event; they run in the order they were registered.
ss.off(handler id) nil Removes the handler or timer with the given id.

Each handler runs under pcall: an error is logged with a traceback and the remaining handlers still run. A handler that fails fifty times in a row is removed.

Timers#

FunctionReturn ValuesDescription
ss.every( seconds interval, function f ) handler id Creates a timer that runs f every interval seconds, from the frame tick. Returns an id for ss.off.
ss.after( seconds delay, function f ) handler id Creates a timer that runs f once, delay seconds from now. Returns an id; ss.off before the timer fires cancels it.

Timers run off the frame tick with the frame's real elapsed time, in every app state. They are not tied to the race clock: a timer started in a race keeps counting through the menus and after the race has ended, so a timer that belongs to a race should be stopped from a race_end handler. A long frame delivers a due timer on the next tick; timers do not catch up. For a sequence of waits in one piece of code, see Routines.

Signals#

FunctionReturn ValuesDescription
ss.signal( string name, vararg args ) integer woken Wakes every routine waiting on the given name via ss.wait_signal, passing it the arguments. Returns the number of routines woken.

Mods#

FunctionReturn ValuesDescription
ss.mods() table of table mods Returns a table of every mod the start-up scan found, in load order, whether or not it has scripts. Each entry is a table with the mod's name and dir.

Saved data#

FunctionReturn ValuesDescription
ss.save_data() boolean saved Writes ss.data to disk. Returns false, with a log line, when the table cannot be saved. See ss.data.
ss.reset_data() nil Empties ss.data and removes its file.

Fields#

TypeFieldRead-only?Description
string ss.mod.name Yes The mod's name: the folder, or the zip without its extension, under Mods.
string ss.mod.dir Yes The mod's folder, as an absolute path.
string ss.game.state Yes The current app state: boot, frontend, loading or race. See Game and race states.
seconds ss.game.time Yes Seconds since the hook loaded.
integer ss.game.frame Yes The number of frames ticked so far.
integer ss.api_version Yes The API's version. Currently 1.
table ss.data No The mod's saved data: a plain table that persists between runs. See ss.data.
string ss.data_path Yes The file ss.data is written to.

Classes#

The rest of the API consists of classes, each with a page of its own:

  • ss.race, the running race.
  • ss.players, the players of the race; ss.player is the local one.
  • ss.vehicles, the cars; ss.vehicle is the local player's. Each has an input.
  • ss.props, the movable props of the level.
  • ss.powerplays, the Power Plays of the level.
  • ss.nemesis, the Nemesis actors: Survival's trucks and the attack modes' cars.
  • ss.vec3, the vector type all of the above use.
  • ss.draw, the on-screen overlay, and ss.ui, widgets on the custom menu screens.
  • ss.params, the game's tweak tree, and ss.mem, raw memory.
  • ss.console, the developer console: command lines, and cvars and commands of the mod's own.
  • ss.routine and the ss.wait_* family.

Removed functions#

os.exit, os.execute, os.remove, os.rename and package.cpath (native modules) are removed from the standard library. Everything else remains, io included, as does ffi.

WARNING: This is not a sandbox. A mod's Lua runs inside the game process with the game's rights, exactly as a DLL mod would, and ffi.cast reaches any address. A Lua mod deserves the same trust as a DLL.

Example#

ss.log("hello from %s", ss.mod.name)       -- string.format when given arguments

local id = ss.on("tick", function(ev)        -- every frame: ev.dt seconds, ev.frame
	if ev.frame % 600 == 0 then ss.log("ten seconds at 60 fps") end
end)

ss.on("state", function(ev)                  -- ev.from, ev.to: "boot", "frontend", "loading", "race"
	if ev.to == "race" then ss.off(id) end
end)

ss.every(1.0, function()
	if ss.vehicle then ss.log("%.0f km/h", ss.vehicle.speed_kmh) end
end)