Skip to content

Memory

Direct memory reads, for offsets you have found yourself.

If you don't already know what offsets are or how to find them, you don't need this namespace. The player and world objects expose everything TSUKI itself uses.

Functions

FunctionReturnsDescription
memory.read(type, address)variesRead a single value at an address
memory.read_chain(type, base, offsets)variesFollow a pointer chain and read the final value
memory.batch_read(entries)tableRead multiple values in one call
memory.get_client_base()integerBase address of the game client module
memory.get_entity_list()integerPointer to the entity list

Supported types

Type stringReads
"float"4-byte float
"double"8-byte double
"int"4-byte signed int
"uint"4-byte unsigned int
"int64"8-byte signed int
"uint64"8-byte unsigned int
"short"2-byte signed int
"ushort"2-byte unsigned int
"byte"1-byte unsigned int
"bool"1-byte boolean
"ptr"Pointer-sized integer
"pointer"Alias for "ptr"

read

Single value at an address.

lua
local base = memory.get_client_base()
local some_offset = 0x1A2B3C4
local x = memory.read("float", base + some_offset)

read_chain

Follow a pointer chain. base is used directly as a starting address (not dereferenced). The first offset is added to base and that address is dereferenced as a pointer: Read<ptr>(base + offsets[1]). Each subsequent offset except the last follows the same pattern. The final offset is added and read as the target type.

lua
-- Equivalent to: *(float*)(*(*(base + o1) + o2) + o3)
local hp = memory.read_chain("float", base, { 0x10, 0x28, 0x4C })

batch_read

Read many values in one round trip. Cheaper than calling read in a loop.

Each entry is a positional array { type_string, address } - the type string is [1] and the address is [2]. Named keys are not supported.

lua
local results = memory.batch_read({
    { "float", 0x12340000 },
    { "int",   0x12340004 },
    { "ptr",   0x12340008 },
})
-- results[1], results[2], results[3]

get_client_base / get_entity_list

lua
local client = memory.get_client_base()
local list   = memory.get_entity_list()

Use these as starting points if you have offsets relative to the client module or relative to the entity list.

Caveats

  • Bad addresses return 0 or nil rather than crashing.
  • batch_read silently truncates the input to 64 entries. Entries past index 64 are ignored with no error.
  • Within a batch_read result, entries with address 0 or an unrecognised type string return nil (not 0) at that index.
  • Offsets shift between game patches. TSUKI updates its offsets server-side; your own scripts have to update theirs.
  • Memory reads are slower than the player/world API. Cache results if you're reading the same address every tick.