# 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](/base/cocos/)'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.

## Reading a field

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.

## Stepping to a nested object

#### h:unity

`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

`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.

```lua
-- 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`](/base/cocos/) / [`objc`](/base/objc/) and then `n:field(...)`.