Skip to content

Lua API

BlueShank edited this page Sep 1, 2026 · 2 revisions

Once a realm is up, a global crashcapture table is available:

crashcapture.set("timeout", 30) -- seconds before a freeze is declared
crashcapture.set("loopbreak", false)
print(crashcapture.get("timeout")) -- 30
crashcapture.pulse() -- manual heartbeat
crashcapture.frametime() -- returns a table of timing metrics
crashcapture.set("profile", true) -- start the Lua call profiler
crashcapture.profile(10) -- top 10 hooks/timers by self time
crashcapture.profile_reset() -- zero the counters, start a fresh window
crashcapture.patches() -- list the compiled-in engine patches and their state
crashcapture.patch("gm.phys.contact_stale_core", false) -- disable one
crashcapture.patch("gm.phys.contact_stale_core") -- re-enable it

In plugin mode the Lua table appears a little after the realm comes up (it's attached on the next game frame, not synchronously like require). Don't guess when it's ready, listen for the crashcapture.ready hook or poll crashcapture.get("ready") (see Knowing when it's ready).

Reference

  • crashcapture.set(key, value)
    • Change a setting at runtime.
    • Keys mirror the settings, lower-cased and without the CRASHCAPTURE_ prefix.
    • Booleans and numbers are both accepted where the setting is numeric.
  • crashcapture.get(key)
    • Read the current value of a setting.
  • crashcapture.pulse()
    • Feed the freeze heartbeat manually.
  • crashcapture.frametime()
    • Table of per-frame timing metrics (frame times, and on Linux the server physics tick).
    • Collected while frame_profile is on.
  • crashcapture.dump()
    • Write a report right now, in-place of where this was called from.
    • See Manual Dump.
  • crashcapture.profile([limit])
    • Lua call profiler results, sorted by self time.
    • See Lua Profiler.
  • crashcapture.profile_reset()
    • Zero the profiler counters and start a fresh window.
  • crashcapture.patches()
    • List the compiled-in engine patches and their state.
    • See Patcher.
  • crashcapture.patch(id [, enabled])
    • Enable or disable one patch by id, or re-enable it when called without enabled.
    • Returns ok, status, saved.
    • See Patcher.
  • crashcapture.phys_pause(pause)
    • Linux-only diagnostic to pause/resume physics, returns applied, state.
    • Deprecated due to the existing physenv.SetPhysicsPaused( boolean pause ).

Settings keys

Keys mirror the settings, lower-cased and without the CRASHCAPTURE_ prefix: timeout, hang_kill, max_age_days, loopbreak, phys_resume, phys_recover, phys_pin, phys_hook_ms, phys_resolve_delay, debug, engine_error, frame_profile, profile, profile_window, report_debounce, hang_map, hang_map_samples, hang_map_interval_ms, firstchance, window_watchdog, lua_heartbeat, manual_dump, symbols, and disable.

dir, script, memapi and phys_hook are launch-config only: get reads them, set is refused (they're decided before Lua exists, and memapi would be a way to grant itself the unsafe mem.* API).
console is not exposed to Lua at all.

Runtime behavior notes:

  • Raising timeout from 0 starts the watchdog, enabling lua_heartbeat installs the heartbeat timer; set("disable", true) disarms the plugin and false re-arms it.
  • max_age_days is only read at startup, so setting it from Lua only affects the next run, dir and script are launch-config only for the same reason.
  • phys_hook_ms applies to the next physics tick and is clamped to 20 minimum, the same as the environment variable.

Knowing when it's ready

Loading as a binary module (require) installs the crashcapture table synchronously, so it's there the moment require returns.
In plugin mode it's attached a little later, on the first game frame after the realm comes up.
Rather than guessing or polling for the table, use either of these:

crashcapture.ready hook - fired once per realm, on the game thread at a safe tick, as soon as the table is installed and usable:

hook.Add("crashcapture.ready", "configure_crashcapture", function(info)
    print("[Crash Capture] ready in", info.realm) -- "server" / "client" / "menu"
    crashcapture.set("timeout", 30)
end)

The info table carries realm, side ("server"/"client"), version, os, and arch.

crashcapture.get("ready") - a boolean for code that may load after the hook already fired (the hook is one-shot, so a late listener would miss it):

if crashcapture and crashcapture.get("ready") then
    crashcapture.set("timeout", 30)
end

Clone this wiki locally