Entities
The most used part of the surface. Enumerating the world, holding handles safely across frames, and reading or writing transforms.
Enumerating the world and checking whether a handle still refers to something.
EntityId
The index says where, the generation says when. When an entity despawns and the slot is reused, the generation increments, so a stale handle compares unequal to the new occupant instead of silently pointing at it. This is why holding an id across frames is safe.
struct EntityId { index: u32, generation: u32 }; // packed into one u64An EntityId is safe across frames because of the generation. A
transform, a count, a resolved address or a pointer is not.
Enumerating
Every live entity this frame. One pool read host-side, cached for the frame, so six mods calling it cost one crossing between them.
entities on this gameEntities of one kind. Kind names come from the pack.
npc or itemEntities inside a sphere. Filtered host-side, so only survivors cross the boundary. A pack with a spatial index answers this natively; otherwise the core filters a snapshot.
Whether that exact handle still resolves. A reused slot returns false because the generation moved.
Live entity count. A pack with a live counter answers without building a snapshot.
Filters compose host-side
The whole chain is one crossing. Filtering happens where the data already is, and only surviving ids come back.
auto targets = f.entities() .alive() .of_kind("npc") .within(me_pos, 80.0f) .excluding(me);
Where things are, and moving them where the pack allows it.
Position, rotation and scale for one entity.
{ pos: Vec3, rot: Quat, scale: Vec3 }, metres and radiansThe same for many. One crossing whatever the length, and per-entity failures come back in place rather than failing the batch.
auto ids = f.entities().alive(); auto xs = f.entities().transforms(ids); // 1 crossing, not ids.size()
Write it back.
writable at init rather than discovering it here.Whether writes are available at all on this game.
For games with component systems. Frequently unanswered, and that is fine.
Whether an entity carries a component.
Everything carrying one. On an ECS game this maps onto archetypes and is cheap.
The component’s bytes, shaped by the pack’s layouts.
On a game without components a pack either synthesises a few sensible names or
leaves this unanswered, so has() returns Denied
rather than a confident false.