For the complete documentation index, see llms.txt. This page is also available as Markdown.

Hooks

onSuccess and onFail let a hack point fire something on the client, on the server, or run an inline function when the minigame ends. Every hack point supports them, and every hack type in cfg.hacks.types supports defaults that apply when a point does not override.


Where hooks live

Three layers, most-specific first. Only one wins per side, hooks do not merge:

  1. Per-point override, on the entry in data/saved_minigames.lua.

  2. Per-type default, on the hack type in cfg.hacks.types.

  3. Global default, cfg.hacks.onSuccess / cfg.hacks.onFail.

The first one that exists wins. If a point sets onSuccess, the type and global defaults are ignored for success, even if the point does not set onFail, the fail hook still falls through to the type or global.


Shape

onSuccess = {
    fn          = function(ctx) print('done') end,
    clientEvent = 'mypack:client:openDoor',
    serverEvent = 'mypack:server:openVault',
    args        = { 'vault_1', 42 },
}

Every field is optional. Any subset works. All that are present fire.

Field
Runs where
Notes

fn

client

Called with a context table. Not serialisable

clientEvent

client

TriggerEvent(clientEvent, args...)

serverEvent

server

TriggerServerEvent(serverEvent, args...)

args

both

Passed as varargs to whichever event fires


Context table (fn)

The inline function receives a single table:

Great for one-off hacks. Not durable, see the auto-save warning below.


Persistence

data/saved_minigames.lua is rewritten on every /create_minigame and /remove_minigame. It serialises Lua values, but functions are not serialisable, so a hook with fn = function() ... end on a saved point gets dropped on the next auto-save and a warning prints:

Two ways out:

  1. Use clientEvent or serverEvent and put the actual code in a handler somewhere else. That is the recommended path.

  2. Turn off auto-save. cfg.hacks.autoSave = false and the file is never rewritten. The commands still work, they just do not persist.


Examples

Global default that logs to Discord

Every hack point in the world reports its outcome. Per-point overrides still work on top.

Per-type default: laptop always opens a menu

Applies to every laptop_open point that does not set its own onSuccess.

Per-point override in data/saved_minigames.lua

Callsite hook (library mode)

Exports do not support hooks directly, because the export already returns the boolean. Handle the outcome inline:


Ordering

When a hack point ends, the client resolves hooks in this order:

  1. fn fires immediately, on the client.

  2. clientEvent fires next, on the same client.

  3. serverEvent fires last, over the network.

The scenes and cam movement finish first, so a fn that opens a follow-up minigame will not fight the sync-scene for control.


What not to do

  • Do not put secrets in args. The event fires from client to server, so the client owns the payload.

  • Do not use fn for anything you need to survive a /create_minigame reshuffle. Auto-save will drop it. See above.

  • Do not fire a hack point's own event from inside its own hook. That will re-enter the pipeline and softlock.

Last updated