spitari
spitari

spitari docs

best external — docs

HomeBuy

Scripts & GC

getscripts

function getscripts(root: Instance?): { Instance }

Collects LocalScript / Script / ModuleScript under root, or DataModel if omitted. Capped — large places return a truncated list.

getscriptbytecode

function getscriptbytecode(script: Instance): string

Raw bytecode bytes as a Lua string, or "".

decompile

function decompile(script: Instance | string): string

Decompiles via in-process Fission (+ normalize for signed/RSB1). Prefer the explorer decompile button for big ModuleScripts — calling this from a hot script can hitch.

On failure returns a short comment string, not a Lua error.

getscripthash / getgamename

Not implemented (Matcha has these).

getsenv

function getsenv(script: Instance): table

Stub — always {}. External VM has no real script env.

scripts table

All of the functions above are also grouped under a scripts table, same behavior:

scripts.get(root: Instance?): { Instance }        -- = getscripts
scripts.bytecode(script: Instance): string        -- = getscriptbytecode
scripts.decompile(script: Instance | string): string -- = decompile
scripts.env(script: Instance): table              -- = getsenv, stub {}

GC (game Luau heaps)

Scan Roblox Lua states from outside (not your script's tables). Two independent capabilities live under the same setgc/gc.set name — a real GC-control mode and a key/value write mode.

getgc()              -- stats / info table
getgc(true)          -- iterator of table proxies
findgc(key)          -- iterator
findgc(key, value)
findgc(nil, value)
findgc({"A","B",...})-- one walk, map key -> array of proxies
getgc_info()
gcprobe()
getrawkeys(proxy)

Proxies: string-key __index; __newindex for existing number/bool keys only.

Heavy GC walks can hitch the cheat — keep samples small in tests.

setgc — GC control mode

setgc(opt: string, value: any?): any

opt is one of the classic lua_gc verbs, applied to the largest live game Luau state:

opt Effect
"stop" disables the GC (sets threshold to -1)
"restart" re-enables it
"count" returns heap size in KB
"isrunning" returns boolean
"pause" / "setpause" get/set gcpause (0–1000)
"stepmul" / "setstepmul" get/set gcstepmul (0–10000)
"collect" / "step" always errors"collect/step need ingame call", cannot be driven from outside the process

setgc / gc.set — key/value write mode

setgc(key: string | {string}, value: number | boolean): number
gc.set(key, value): number

If the first argument is not one of the GC verbs above (or is a table), setgc scans every live table in every game Luau VM for a string key equal to key (or any key in the array form) whose current value has the same type as value (number or boolean — no strings), and overwrites it in place. Returns how many tables were touched.

setgc("ShootCooldown", 0)          -- zero it everywhere it's found
gc.set("ShootCooldown", 0)         -- identical, table form
gc.set({"FireRate", "Damage"}, 999)

This is a one-shot write — if the game's own code overwrites the field again next tick, the change does not stick. For that, use lockgc / gc.lock.

lockgc / gc.lock — persistent write

lockgc(key: string | {string}, value: number | boolean, interval_ms: number?): number
gc.lock(key, value, interval_ms?): number

Same key/value matching as setgc, but keeps re-writing the value from a background thread instead of writing once. Returns the initial hit count.

lockgc("ShootCooldown", 0)                 -- keep it pinned at 0, default 100ms
gc.lock("Ammo", 999, 250)                  -- pin Ammo=999, re-apply every 250ms
gc.lock({"MinDamage", "MaxDamage"}, 9999)

unlockgc / gc.unlock

unlockgc(key: string?): number   -- returns how many locks were removed
gc.unlock(key?): number

No argument removes all active locks; with a key (or the same comma-joined tag used for a multi-key lock) removes just that one.

gc.locks()

gc.locks(): { { key: string, value: number | boolean, hits: number } }

Lists currently active locks: the key/tag, the pinned value, and how many table nodes are currently being held.

gc table

All GC functions are also grouped under a gc table — same C functions, same behavior as the flat globals:

gc.set(key, value)      -- = setgc
gc.get(...)              -- = getgc
gc.find(...)             -- = findgc
gc.info()                -- = getgc_info
gc.lock(key, value, interval_ms?)   -- = lockgc
gc.unlock(key?)          -- = unlockgc
gc.locks()               -- list active locks
gc.keys(proxy)           -- = getrawkeys
gc.probe()               -- = gcprobe

The legacy flat globals (setgc, getgc, getgc_info, findgc, gcprobe, getrawkeys, lockgc, unlockgc) are unchanged and keep working exactly as before — gc.* is an additional namespaced form, not a replacement.