Reference
ss.mem
The mem function reads and writes the game's memory at any address, in the same way as LunaLua's
mem. Every live object additionally has a mem
method, a memdump method and an address field relative to its own record; those,
and the offsets found so far, are documented under Instance Memory Offsets on the
vehicle, prop and
actor pages. Players have the same three,
relative to their game logic object. This page covers the global addresses.
Static members#
These elements are static to the class itself and can be accessed like so:
local mode = ss.mem(0xd2c728, "int")Static functions#
| Function | Return Values | Description |
|---|---|---|
ss.mem(
integer address,
string type
) |
any value | Returns the value of the given type at the given address. Returns nil when the address is not mapped. |
ss.mem(
integer address,
string type,
any value
) |
boolean written | Sets the value of the given type at the given address. Returns whether the write could be made: false for an unmapped page. A read-only page, such as code or constants, is unprotected for the write and protected again afterwards. |
ss.mem.readable(
integer address,
integer size
) |
boolean readable | Returns whether the given number of bytes at the given address are mapped. This is the same test a read makes. |
Types#
The type names a read or write accepts. Each entry lists its aliases.
| Type | Field | Description |
|---|---|---|
| integer | byte, u8 |
One unsigned byte. |
| integer | sbyte, i8 |
One signed byte. |
| integer | word, u16 |
Two bytes, unsigned. |
| integer | short, i16 |
Two bytes, signed. |
| integer | dword, u32, pointer |
Four bytes, unsigned. A pointer is read and written as one of these. |
| integer | int, i32 |
Four bytes, signed. |
| number | float, f32 |
A single-precision floating point value. |
| number | double, f64 |
A double-precision floating point value. |
| boolean | bool |
One byte, read as true for any value other than 0. A write stores 1 or 0. |
| string | string |
A NUL-terminated string. A number as the third argument is the longest string to read, 256 by default, so ss.mem(addr, "string", 2) reads two characters and never writes. A write takes a string and stores it with its terminator. |
Guards#
Reads are guarded: an address whose page is not mapped returns nil rather than crashing, and
ss.mem.readable asks the same question without reading. Writes return true, or
false for an unmapped page. Each guarded access is a page query, which takes tens of microseconds
on a virtual machine: suitable for a script that reads a few values when something happens, not for thousands
of reads per frame. LuaJIT's ffi remains available for unguarded, faster access.
Translated builds#
On the translated builds (Linux, Windows, macOS, Android and iOS) the same addresses are guest memory and
ss.mem reaches them in the same way. The hook's own patches differ between builds, however, so
anything a mod depends on is better served by a seam in the API than by a write to an address.
Global memory offsets#
These addresses can be read and written with ss.mem. They are absolute.
| Field | Fieldtype | Description |
|---|---|---|
0xd2c728 |
int |
The race's mode index. 6 means no mode: the front end, or a dev-boot race, which never sets it. Use field ss.race.mode_index |
0xd13e14 |
byte |
The engine log's master enable. |
0xd65f8c |
pointer |
The engine log's filter callback. |
0xd59698 |
pointer |
The Nemesis selection object. The 24 slot indices that ss.race.nemesis_slots writes are at +0x14 from there. |
Example#
local mode = ss.mem(0xd2c728, "int") -- the race's mode index
ss.mem(0xd13e14, "byte", 1) -- enables the engine log
local vx = ss.vehicle:mem(0x17bc, "float") -- the car's cached velocity x, through the instance method
ss.vehicle:memdump(0x1750, 0x1810) -- the position, rotation and velocity block, dword by dword