Registry class

Central entity management system.

Manages three independent handle spaces:

  • GlobalEntityHandle (GHandle) — internal record identity; indexes Records[].
  • EntityHandle (LHandle) — OOP / Construct-facing handle; indexes LocalToRecord[].
  • EntityNetHandle (NetHandle) — network replication handle; indexes NetToRecord[].

Index 0 is reserved / invalid in all three spaces.

Creation flow:

  1. CreateInternal(classID, span<GHandle>) — allocates records and archetype slots.
  2. MakeEntityHandle(GHandle, classID) — allocates a local index, wires LocalToRecord.
  3. Public API (Create<T>, CreateByClassID) — wraps the above, returns EntityHandle.

Destruction flow:

  1. Destroy(LHandle) — defers GHandle to PendingDestructions.
  2. ProcessDeferredDestructions — removes from archetype, calls FreeGlobalHandle.
  3. FreeGlobalHandle — reclaims record index, queues local / net handle recycling.
  4. ConfirmLocalRecycles / ConfirmNetRecycles — moves pending → free after the safety window.

Public types

struct ServerEventEntry

Public static functions

static void WriteEntityTransformFields(void*const* fieldArrayTable, const Archetype* arch, uint32_t localIdx, SimFloat posX, SimFloat posY, SimFloat posZ, SimFloat rotQx, SimFloat rotQy, SimFloat rotQz, SimFloat rotQw)

Constructors, destructors, conversion operators

Registry()
Registry(const EngineConfig* config)
~Registry()

Public functions

template<typename T>
auto Create() -> EntityHandle
template<typename T, std::invocable<T&> Fn>
auto Create(Fn&& fn) -> EntityHandle
template<typename T>
auto Create(size_t count) -> std::vector<EntityHandle>
template<std::invocable<EntityRecord&, void**> Fn>
auto CreateByClassID(ClassID classID, Fn&& fn) -> EntityHandle
void Recreate(EntityHandle& inHandle)
template<typename T>
void RecreateAs(EntityHandle& inHandle)
void RecreateAs(EntityHandle& inHandle, const EntityHandle& asHandle)
void Destroy(EntityHandle lHandle)
void DestroyByGlobalHandle(GlobalEntityHandle gHandle)
void ForceDestroyByGlobalHandle(GlobalEntityHandle gHandle)
void ProcessDeferredDestructions()
auto ReclaimedSlots() -> std::vector<uint32_t>&
void ConfirmTombstone(uint32_t recordIndex)
auto IsTombstoned(uint32_t recordIndex) const -> bool
template<typename T>
auto HasComponent(EntityHandle lHandle) -> bool
template<typename... Components>
auto ComponentQuery() -> std::vector<Archetype*>
template<typename... Classes>
auto ClassQuery() -> std::vector<Archetype*>
void InvokeScalarUpdate(SimFloat dt)
void InvokePrePhys(SimFloat dt)
void InvokePostPhys(SimFloat dt)
void TickDefrag(TrinyxJobs::WorldQueueHandle wq)
void ForceDefragSync()
auto GetVolatileCache() -> ComponentCache<CacheTier::Volatile>*
auto GetTemporalCache() -> ComponentCache<CacheTier::Temporal>*
auto SweepAliveFlagsToActive() -> int
auto SnapVisualTransforms() -> uint32_t
auto ApplyFieldEdit(const FieldEdit& edit) -> bool
auto ReadField(EntityHandle entity, ComponentTypeID component, uint8_t fieldIndex, void* out, size_t size) -> bool
auto GetHandleForCacheIndex(EntityCacheHandle cacheIndex) -> EntityHandle
void MarkDiscontinuity(EntityHandle handle)
void MarkDiscontinuity(EntityCacheHandle cacheIndex)
auto ApplyPendingVisualSnaps() -> uint32_t
auto Retire(EntityHandle handle) -> bool
auto Revive(EntityHandle handle) -> bool
auto IsAlive(EntityCacheHandle cacheIndex) -> bool
True if the entity in cacheIndex is Alive in the current write frame.
auto GetLocalHandle(GlobalEntityHandle gHandle) -> EntityHandle
The local handle of a live entity, or an invalid handle.
void SetDefragEnabled(bool bEnabled)
Defrag relocates entities; edit worlds turn it off so their history stays index-stable.
auto CheckAndCorrectEntityTransform(const EntityTransformCorrection& correction) -> bool
void PushServerEvent(ServerEventEntry entry)
void PushAppliedServerEvent(std::function<void()> replay)
Record an effect already written into the current write frame; keyed at that frame.
void ReplayServerEventsAt(uint32_t frame)
void ApplyPendingServerEventsBefore(uint32_t frame)
At a rollback's rewind point: apply events keyed before frame that never reached the ring.
void PruneServerEvents(uint32_t oldestFrame)
Drops applied events older than oldestFrame; unapplied events wait for their rewind.
void PushEntityReinitEvent(GlobalEntityHandle gHandle, uint32_t frame)
auto GetTotalChunkCount() const -> uint32_t
auto GetTotalEntityCount() const -> uint32_t
auto GetArchetypes() const -> const auto&
auto GetRecordByCache(EntityCacheHandle cacheHandle) const -> EntityRecord
auto GetRecord(EntityHandle handle) const -> EntityRecord
template<typename T, void(T::*)(uint32_t, uint32_t) MemFn>
void BindOnCacheSlotChange(EntityHandle handle, T* obj)
template<typename T, void(T::*)(uint32_t, uint32_t) MemFn>
void UnbindOnCacheSlotChange(EntityHandle handle, T* obj)
auto FindEntityByLocation(EntityCacheHandle cacheHandle) const -> GlobalEntityHandle

Public variables

std::atomic<uint32_t> RenderAck
uint32_t LastPublishedFrame
bool RenderHasAcked
bool ReplicationActive

Function documentation

std::vector<uint32_t>& Registry::ReclaimedSlots()

Cache slots whose entity has been reclaimed since this list was last cleared. A slot may be handed to a new entity at any time after it appears here, so whoever keeps something per slot outside the registry (physics keeps a body) lets go of it and clears the list, once a frame, straight after ProcessDeferredDestructions. Brain thread.

uint32_t Registry::SnapVisualTransforms()

Set every entity's visual position to its simulation position in the current write frame, for archetypes carrying both CTransform and CVisualTransform. The visual transform normally follows through PostPhysics blending; a paused world never simulates, so edits and spawns snap here instead. Returns the number of entities changed (marked Dirty | DirtiedFrame).

bool Registry::ApplyFieldEdit(const FieldEdit& edit)

Apply an editor field write in the current write frame (cold fields: in the chunk) and mark the entity Dirty | DirtiedFrame. Brain thread only — reach it through WorldBase::SubmitFieldEdit. Returns false (and writes nothing) for a stale handle, an unknown field, or a size mismatch.

bool Registry::ReadField(EntityHandle entity, ComponentTypeID component, uint8_t fieldIndex, void* out, size_t size)

Copy one field of one entity from the current write frame. Brain thread only (or while the logic thread is not running). Returns false for a stale handle, unknown field, or size mismatch.

EntityHandle Registry::GetHandleForCacheIndex(EntityCacheHandle cacheIndex)

The existing local handle of the entity in cache slot cacheIndex (invalid if none). For tools that select by slot (the editor) and must name entities by handle in edits.

void Registry::MarkDiscontinuity(EntityHandle handle)

The entity jumped (teleport, respawn, relocation): render shows its current state this frame instead of interpolating from the previous one. Brain thread, write frame.

uint32_t Registry::ApplyPendingVisualSnaps()

Snap VisPos to Pos for entities marked discontinuous since the last call, so logic-side visual smoothing (CVisualTransform::VisBlend) doesn't glide them across the jump either. Brain thread, after PostPhysics. Returns the number snapped.

bool Registry::Retire(EntityHandle handle)

Take the entity out of the world without destroying it: clears Active and Alive, so it stops ticking, rendering, and serializing, but its record, slot, and handle stay reserved. Revive puts it back (Active | Alive) under the same handle. Used by editor history so undoing a delete restores the same entity. Brain thread. Returns false for a stale handle.