Skip to content

reflect

Read fields off native objects by name, guided by the engine’s own type metadata. Gated behind the reflect capability, so it is nil unless granted. This is the il2cpp / cocos field-walk seam.

You get a handle from the engine (a cocos node’s n:field(...), or a game namespace that hands one out), then step field by field and read a typed value at the end. Every handle is frame-scoped: a handle taken on an earlier frame is stale and using it raises an error. Take it and read it in the same frame.

On a field handle:

Method Returns Description
h:i32() integer|nil 32-bit int at the field.
h:i64() integer|nil 64-bit int.
h:f32() number|nil float.
h:f64() number|nil double.
h:bool() boolean|nil bool.

Each returns nil when the address is unreadable or the field was not found.

h:unity(image: string, namespace: string, name: string): handle|nil

Reads the field as a Unity object pointer and returns a new handle typed as that class (image is the assembly image, e.g. "Assembly-CSharp"), so you can index the next field by name. Returns nil when the class is unknown or the pointer is null.

h:cocos(): handle|nil

Reads the field as a cocos object pointer and returns a handle for it, carrying the parent’s field shape. Errors if the current handle is not a cocos field.

-- read enemy.health two hops in, on a Unity build
local player = reflect_handle_from_game() -- a handle the game exposes
local hp = player:unity("Assembly-CSharp", "", "Hero"):i32()

On a cocos build, prefer reaching the object through cocos / objc and then n:field(...).