Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit61a33237e0

README.md

component_field_route

One rule for which access route serves a component's fields, shared by every API that names an entity, a component and a field: Entity.getField, Entity.setField, Entity.patch, entity.batchWrite and entity.batchRead.

Two routes exist, because two kinds of component do:

  • reflect route — a component backed by an engine struct (Transform, MeshInstance, Physics). __reflect resolves its fields through the reflect registry.
  • component route — a component declared in Luau (Model, Text3D, and every other .component folder). Its field values live on the component instance, so the component ref (entity(id).component.get(name)) is what reaches them.

The reflect registry holds engine structs only, so a component declared in Luau resolves on the second route and nowhere else. Dispatching on which route serves the name is what lets one call site write Model.tintBlend and Transform.position the same way.

Exports

  • M.isReflected(component: string) -> boolean — whether the reflect registry holds this component.
  • M.requireComponentType(api: string, component: string) — raise unless the name is one this engine knows, either as an engine struct or as a declared .component.
  • M.componentRef(entityId: string, component: string) -> ComponentRef? — the component ref serving component on that entity, or nil.
  • M.declaredFields(ref: ComponentRef) -> { [string]: boolean } — the public and private field names the ref declares.
  • M.reportMissingField(api, component, field, outcome) — report a field the component does not declare.
  • M.reportEntityWithoutComponent(api, entityId, component, outcome) — report one entity that does not carry it.
  • M.reportEntitiesWithoutComponent(api, component, missing, total, outcome) — report a call's entities that do not carry it, as one line.
  • M.readField(api, entityId, component, field) -> any — read one field through whichever route serves it.
  • M.writeField(api, entityId, component, field, value) -> boolean — write one field through whichever route serves it.

Usage

local Route = require("@builtin::modules.component_field_route")

Route.writeField("entity.batchWrite", id, "Model", "tintBlend", 0.5)
local blend = Route.readField("entity.getField", id, "Model", "tintBlend")

What a caller is told

situationresult
a component name nothing declaresraises, naming the component
a component the entity does not havethe neutral value, reported by the route
a field the component does not havethe neutral value, reported at error level

api is the surface the caller used; it is named in every diagnostic so the line points at the call rather than at the machinery underneath.

A report repeats at most once every five seconds per (api, component, field), the budget the reflect route spends on the same mistake, so a per-frame loop over a wrong name costs one line rather than one per frame — and a batch names the entities that do not carry the component once for the call rather than once each.