memory
Work with owned buffers, pointer lifetimes, and memory operations.
The memory interface provides owned local buffers and access to known local-process addresses. It does not expose an arbitrary C++ function-call interface. Native hooks are provided separately through natives.hook. The reference here describes the available operations without prescribing game-address patches or undocumented layouts.
Namespace reference
memory.alloc
Zeroed buffer, 1..1,048,576 bytes, aligned to 8 bytes.
text
memory.alloc(bytes)Returns: Owned Pointer
memory.pointer
Wraps an exact integer or unsigned decimal/hex address string; wrapping alone does not validate memory.
text
memory.pointer(address)Returns: Borrowed Pointer
memory.scan
Initial-load phase only; unique executable-region match, otherwise a null pointer.
text
memory.scan(signature)Returns: Borrowed Pointer
memory.scan_all
Initial-load phase only; zero matches gives an empty array, more than 512 matches raises an error.
text
memory.scan_all(signature)Returns: Pointer array
memory.patch
Initial-load phase only; records original bytes and a replacement for conditional restoration.
text
memory.patch(pointer, bytes)Returns: Nothing
“Initial-load phase” means execution of the entry chunk, including a module required during that execution. It does not include later menu or timer callbacks. Registering a callback does not itself end the phase, but scanning and patching should be resolved during initialization.
Signatures use whitespace-separated hexadecimal bytes and ? or ?? wildcards. They must contain at least one concrete byte and occupy 1–1,024 characters. The scan region is executable memory in the main game image. A failed or ambiguous unique scan returns a null Pointer, not nil.
Pointer reference
All methods use colon syntax. pointer.address is a read-only numeric property.
pointer:is_null
Whether the address is zero.
text
pointer:is_null()Returns: Boolean
pointer:add
Signed offset with arithmetic-overflow checks; keeps an owned buffer's ownership.
text
pointer:add(offset)Returns: Pointer
pointer:rip
Resolves a signed 32-bit relative displacement from a known instruction layout.
text
pointer:rip(displacement_offset, instruction_length)Returns: Pointer
pointer:read_bytes
Copies 1..1,048,576 bytes.
text
pointer:read_bytes(count)Returns: Binary string
pointer:write_bytes
Writes a nonempty binary string up to 1 MiB to writable memory.
text
pointer:write_bytes(bytes)Returns: Nothing
pointer:read_string
Reads a terminated string; default limit 4,096, valid range 1 byte–1 MiB.
text
pointer:read_string([limit])Returns: String
pointer:read_u8
Reads an unsigned 8-bit value.
text
pointer:read_u8()Returns: Integer
pointer:read_u16
Reads an unsigned 16-bit value.
text
pointer:read_u16()Returns: Integer
pointer:read_u32
Reads an unsigned 32-bit value.
text
pointer:read_u32()Returns: Integer
pointer:read_i32
Reads a signed 32-bit value.
text
pointer:read_i32()Returns: Integer
pointer:read_i64
Reads a signed 64-bit value.
text
pointer:read_i64()Returns: Integer
pointer:read_float
Reads a 32-bit float.
text
pointer:read_float()Returns: Number
pointer:read_double
Reads a 64-bit floating-point value.
text
pointer:read_double()Returns: Number
pointer:read_pointer
Reads an address; does not inherit ownership of the referenced allocation.
text
pointer:read_pointer()Returns: Borrowed Pointer
pointer:write_u8
Writes an unsigned 8-bit value.
text
pointer:write_u8(value)Returns: Nothing
pointer:write_u16
Writes an unsigned 16-bit value.
text
pointer:write_u16(value)Returns: Nothing
pointer:write_u32
Writes an unsigned 32-bit value.
text
pointer:write_u32(value)Returns: Nothing
pointer:write_i32
Writes a signed 32-bit value.
text
pointer:write_i32(value)Returns: Nothing
pointer:write_i64
Writes a signed 64-bit value.
text
pointer:write_i64(value)Returns: Nothing
pointer:write_float
Writes a 32-bit float.
text
pointer:write_float(value)Returns: Nothing
pointer:write_double
Writes a 64-bit floating-point value.
text
pointer:write_double(value)Returns: Nothing
Use values representable by the named type. There are no read_u64, write_u64, read_vec3, write_string, or explicit free methods in this binding. Binary byte reads/writes may contain zero bytes; they use the buffer limit rather than the text limit.
read_string() raises an error when no terminator is found within its limit; it does not silently truncate. For rip(), displacement offset must be nonnegative, instruction length must exceed that offset, and at least four displacement bytes must fit within the instruction length. The result is base + instruction_length + signed_displacement.
Owned allocations remain alive while their owning handles remain referenced. Derived pointers preserve that ownership, but access beyond the original logical buffer remains invalid. Pointer arithmetic alone does not prove that the result lies inside the buffer. A pointer read from a buffer is a borrowed address, not a new ownership relationship.
Reads and writes validate the requested range. Ordinary writes require writable pages and do not change page protections. Page accessibility does not establish that a game object is still alive; revalidate borrowed addresses and avoid retaining them across session/lifetime changes.
Owned-buffer example
This example uses only memory allocated by the script:
lua
local buffer = memory.alloc(16)
buffer:write_u32(1234)
buffer:add(4):write_float(2.5)
buffer:add(8):write_bytes("Lua\0")
assert(buffer:read_u32() == 1234)
assert(buffer:add(4):read_float() == 2.5)
assert(buffer:add(8):read_string(4) == "Lua")
util.log("Owned buffer checks passed")Tracked patch cleanup
memory.patch() allows up to 64 tracked patches per script. It records the original bytes and retains owned-buffer storage when applicable. It uses the shared memory writer for protection changes and instruction-cache handling. Failure raises an error.
Cleanup processes patches in reverse order. It restores an original range only when the current bytes still equal that script's replacement, avoiding overwriting a later owner. A failed or conflicting restore is reported; shutdown still proceeds and clears the patch records. Do not describe restoration as guaranteed, transactional rollback of all game state, or a mechanism that keeps retrying after unload. There is no public manual-unpatch function.