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
| Function | Returns | Description |
|---|---|---|
memory.read(type, address) | varies | Read a single value at an address |
memory.read_chain(type, base, offsets) | varies | Follow a pointer chain and read the final value |
memory.batch_read(entries) | table | Read multiple values in one call |
memory.get_client_base() | integer | Base address of the game client module |
memory.get_entity_list() | integer | Pointer to the entity list |
Supported types
| Type string | Reads |
|---|---|
"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.
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.
-- 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.
local results = memory.batch_read({
{ "float", 0x12340000 },
{ "int", 0x12340004 },
{ "ptr", 0x12340008 },
})
-- results[1], results[2], results[3]get_client_base / get_entity_list
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
0ornilrather than crashing. batch_readsilently truncates the input to 64 entries. Entries past index 64 are ignored with no error.- Within a
batch_readresult, entries with address0or an unrecognised type string returnnil(not0) 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.