Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

ref

Entity proxy metatable layer. Replaces the per-call closure-pushing entity proxy (push_entity_proxy in crates/zero_scripting/src/ffi_callbacks.rs) with a thin Luau metatable that calls into the __native_transform.* / __native_entity.* flat FFI bindings. The user-facing API is unchanged: entity(id).localPosition = { x, y, z }, entity(id).despawn(), entity(id).name, etc. all still work.

After warm-up, steady-state allocation is zero: same id returns the same proxy (weak-valued cache), sub-proxies are lazily allocated once and cached on the proxy, and each method binding is a closure created on first access and cached as __m_<name>.

Exports

  • M.build(id: string) -> any — entity proxy factory. Returns a cached proxy when one exists; otherwise allocates and caches a fresh one. Also bound as _G.__build_entity_proxy for the Rust-side push_entity_proxy call.
  • M.EntityProxyMT, M.PositionProxyMT, M.RotationProxyMT, M.LocalPositionProxyMT, M.LocalRotationProxyMT, M.LocalScaleProxyMT, M.LossyScaleProxyMT, M.TransformProxyMT, M.AttributeProxyMT — exported metatables; consumers that want to extend the proxies can read them, but the proxies are sealed externally (every __newindex errors).

Usage

local EntityProxy = require("@builtin::modules.api.engine.entity.ref")

local proxy = EntityProxy.build("some-entity-id")
proxy.localPosition = { 0, 1, 2 }
proxy.localRotation.eulerAngles = { 0, 90, 0 }
print(proxy.name)
proxy.despawn()

Notes

  • World vs local space (post Bevy hierarchy migration):
    • .position / .rotation are world-space — engine back-computes Transform.{translation, rotation} on set, decomposes the world matrix on get.
    • .localPosition / .localRotation / .localScale are parent-relative direct reads/writes on Transform.*.
    • .lossyScale is read-only world-space scale (approximate under non-uniform parent scale + rotation; mirrors Unity).
    • .worldMatrix() answers the whole composed object-to-world matrix as 16 column-major numbers, translation in elements 13, 14, 15 — the placement the renderer draws the entity's geometry at, carrying the skew a decomposition into position / rotation / scale folds away. Also readable as .transform.worldMatrix().
    • Bare .scale was removed — accessing it raises an error pointing callers at localScale / lossyScale.
  • Sealed proxies: every proxy errors on __newindex (sealing). Mutations go through position.set / attribute.set / etc., not direct field writes.
  • Caching: the entity-proxy cache is keyed by id with weak values (__mode = "v"), so dropped proxies are GC'd. Within one proxy, the M_PREFIX-keyed cache survives until the proxy itself is collected.
  • The .component sub-proxy is built by __native_entity.component_subproxy — Rust-side helper that constructs the ~15-closure component-proxy table once per entity. Subsequent .component accesses hit the cached entry.