spitari
spitari

spitari docs

best external — docs

HomeBuy

Memory

Low-level primitives for reading/writing the Roblox process by raw numeric address — not through Instance userdata. This is a reverse-engineering layer: there is no bounds checking, no type checking against a real property, and no safety net. A wrong or stale address can read garbage or crash the game.

addrof(instance) turns an Instance userdata into the raw address these functions expect; a number is also accepted directly (already-an-address, or computed with an offset).

Read / write primitives

rdq(addr): number?      -- uint64
rdd(addr): number?      -- uint32
rdw(addr): number?      -- uint16
rdb(addr): number?      -- uint8
rdf(addr): number?      -- float

wrq(addr, value): boolean
wrd(addr, value): boolean
wrw(addr, value): boolean
wrb(addr, value): boolean
wrf(addr, value): boolean

Reads return nil on an implausible/unreadable address; writes return true/false.

Strings

rdcstr(addr, max: number?): string?   -- raw C string, default max 64 bytes, capped at 512
rdstr(addr): string?                  -- std::string at addr (small-string-optimized, reads the real length)
wrstr(addr, text: string): boolean    -- writes a std::string at addr
wrcontent(addr, text: string): boolean -- writes a std::string for a Content field and resets its cached URI scheme

wrstr handles both the inline (< 16 bytes) and heap-allocated std::string layouts — for long strings it allocates a fresh buffer in the game process via gatecall and repoints the string at it (the old buffer is intentionally not freed, since the engine may still be reading it for rendering).

wrcontent is wrstr plus clearing the scheme byte Roblox caches alongside a Content field (texture/sound/mesh id string). Content fields remember whether their string looked like rbxasset://, rbxassetid://, http://, etc.; without resetting that cache the engine keeps parsing your new string using the old scheme and the asset never loads. Used for skybox faces, decals and similar id fields — see scripts/custom_skybox.lua and scripts/weather.lua.

local at = addrof(sky)
wrcontent(at + 0xf8, "rbxassetid://15536110634")  -- Sky face texture, offset from reflect_probe.lua

Reflection

refname(name: string): number?           -- interned RBX::Name* for a string, or nil
refcreator(name: string | number): number? -- class creator/factory pointer for a class name (or its RBX::Name* address)
classdesc(addrOrInstance): number?       -- class descriptor pointer of an instance
rbxbase(): number                        -- RobloxPlayerBeta.exe module base address
addrof(instanceOrNumber): number         -- numeric address of an Instance userdata (passthrough for numbers)
get_class(addr): string?                 -- class name of the instance at addr, without a userdata handle
get_name(addr): string?                  -- .Name of the instance at addr

get_class / get_name are also available as mem.get_class / mem.get_name.

Scanning

scanptr(addr, needle: number, span: number?): { number }

Scans span bytes (default 0x400, capped 0x10000) starting at addr for 8-byte-aligned occurrences of the needle qword and returns the list of byte offsets where it was found. Useful for locating a pointer to a known object inside a struct you don't have offsets for yet.

CallGate access

gatecall(fnAddr: number, a0?: number, a1?: number, a2?: number, a3?: number): number?
gatescratch(): number

gatecall invokes an arbitrary function pointer on the real game thread through CallGate — the same mechanism Instance.new and .Parent = use internally (see Instance for how the hijack works). Arguments map to rcx/rdx/r8/r9; the return value comes from rax. On failure it returns nil plus a reason string ("bad function address", "no call gate", "gate timeout").

gatescratch() returns the address of a small (≥ 256 byte) scratch buffer inside the game process, useful as an out-parameter buffer for calls that write their result through a pointer argument instead of returning it in rax.

This is the sharpest edge of the API. Calling the wrong address, or the right address with the wrong calling convention/argument count, can crash or corrupt the game. Prefer the higher-level Instance.new / property setters / mem.wrcontent etc. unless you specifically need to invoke engine code that isn't wrapped yet.

mem table

All of the above are also grouped under a mem table — same functions, same behavior as the flat globals:

mem.rdq / mem.rdd / mem.rdw / mem.rdb / mem.rdf
mem.wrq / mem.wrd / mem.wrw / mem.wrb / mem.wrf
mem.rdcstr / mem.rdstr / mem.wrstr / mem.wrcontent
mem.gatecall / mem.gatescratch
mem.rbxbase / mem.addrof / mem.refname / mem.refcreator / mem.classdesc / mem.scanptr
mem.get_class / mem.get_name

The flat globals (rdq, wrstr, gatecall, get_class, …) are unchanged and keep working exactly as before — mem.* is an additional namespaced form, not a replacement.