Skip to main content

Module ecs

Module ecs 

Source
Expand description

The renderer-free half of the engine’s ECS: the storage mechanism, the per-tick context systems see, and the asset identity + registry layer the build / validate pipeline and the client runtime share.

The storage mechanism is closed-world and carries no engine domain type. It provides the generic primitives only: entities (Entity, Entities), typed storage columns (Column), change ticks (Tick), component masks (ComponentMask) and a join index (JoinIndex), resources (Resources), events (Events), and the per-system access sets (Access) the scheduler uses to run two systems concurrently. Nothing in that half knows about meshes, blobs, or rendering, and none of it stores a type the project did not register at compile time: there is no TypeId-keyed type erasure and no open-world insert of arbitrary external types.

The concrete component set is registered in registry and expanded by define_components!, which pairs the asset-enum dispatch with the storage half from define_component_storage!.

On top of that sit the pieces the engine reaches for: the Component metadata trait, the plain data types the registry and blob format are built from (AssetOrigin, AssetPayload, PayloadLocator, BlobAssetDef, AssetKind), the System behavior trait, and the World: the components, resources, events, payloads, profile, and frame scratch a tick reads and writes, plus the systems that run over them and their schedule. The system table itself (SystemTable) names a host’s own system types, so it is written in the client crate, whose ecs module re-exports everything here under the historical crate::ecs::* paths alongside the ComponentAsset value enum.

The interner that assigns asset identities keeps a per-thread table and lives in concinnity-host. The authoring Registration record lives in concinnity-cook, constructed from the trait’s metadata consts.

Re-exports§

pub use crate::memory::Arena;
pub use locator::PayloadLocator;
pub use handle::AudioClipHandle;
pub use handle::ColorLutHandle;
pub use handle::CubemapTextureHandle;
pub use handle::EnvironmentMapHandle;
pub use handle::FontHandle;
pub use handle::MaterialHandle;
pub use handle::MeshHandle;
pub use handle::ShaderHandle;
pub use handle::SkinnedMeshHandle;
pub use handle::TextureHandle;
pub use handle::de_audio_clip_handle_vec;
pub use handle::de_opt_audio_clip_handle;
pub use handle::de_opt_font_handle;
pub use handle::de_opt_material_handle;
pub use handle::de_opt_mesh_handle;
pub use handle::de_opt_shader_handle;
pub use handle::de_opt_skinned_mesh_handle;
pub use handle::de_opt_texture_handle;
pub use handle::de_texture_handle;
pub use resolver::set_audio_clip_handle_resolver;
pub use resolver::set_font_handle_resolver;
pub use resolver::set_material_handle_resolver;
pub use resolver::set_mesh_handle_resolver;
pub use resolver::set_shader_handle_resolver;
pub use resolver::set_skinned_mesh_handle_resolver;
pub use resolver::set_texture_handle_resolver;
pub use crate::blob::AssetKind;
pub use crate::blob::BlobAssetDef;
pub use crate::blob::BlobMeta;
pub use crate::blob::MeshBoundsRecord;
pub use crate::blob::PhysicsBudgetRecord;
pub use crate::blob::ResourceKind;
pub use crate::blob::ResourceRecord;
pub use crate::blob::SceneGroup;

Modules§

access_check
Debug-build access validation hooks. PipelineContext accessors report each touch here; the client installs a hook that asserts the touch against the stepping system’s declared Access (tracked client-side, since this crate is no_std and holds no per-thread state). World::step announces which system is stepping through the second hook, for the same reason: the tracking is per-thread and belongs to the host. Compiled out of release builds entirely: release parallel-safety never rests on these checks, only on the executor handing conflicting systems to different waves.
asset_id
Asset identity: names declared in world.jsonl are interned to an AssetId in declaration order, and the blob and the runtime carry only the integer, so every cross-reference lookup is an integer compare.
asset_ref
A typed reference from one asset to another, declared by name.
handle
Per-kind resource handles.
locator
Where an asset’s compiled payload lives in the data blob.
resolver
Name -> id resolution seam.

Structs§

Access
A system’s declared data access.
AtomicTick
The change-tick counter shared across a storage’s columns, atomic so writers of disjoint columns can stamp edits concurrently without sharing &mut. Relaxed ordering: the counter only supplies monotonic values; the column data it stamps is synchronized by the scheduler (join/channel edges), never by the counter itself. Values stay globally monotonic but their exact assignment is interleaving-dependent under concurrency, so tick values must never be hashed, persisted, or compared across columns.
BuiltSystem
A constructed system and the table entry name it was built from.
Clock
A monotonic microsecond source, installed as a world resource by the host.
Column
A dense column of one component type, with its per-row change stamps.
ColumnTicks
The tick stamps a column keeps. changed is the maximum over every kind of write and drives whole-column change detection. added marks the last appended row. bulk marks the last whole-column mutable access, after which every row must be assumed written. structural marks the last row add or removal, after which row positions and membership have moved. A consumer that tracks rows individually reads bulk and structural to decide whether the per-row stamps alone still describe what changed.
ComponentId
A component’s dense id, its bit position in a ComponentMask.
ComponentMask
A set of component ids, one bit each.
ComponentStorage
One Column<T> per registered component type, the entity allocator that stamps each row’s id, the change tick stamped on every structural edit, and the join index that maps an entity to its row in each column. Field columns are the caller’s field idents, reached through the $slot trait; callers never name them directly.
CursorState
The latest sampled cursor state (window pixels, top-left origin), published by InputSystem after each poll. GraphicsSystem reads it when building the next frame’s draw list: follow_cursor sprites are positioned a frame after the input that moved them, and the in-engine cursor stops drawing once the real cursor has left the window (outside_window is false in fullscreen, where the backend confines the cursor, and on backends without window-bounds tracking).
DesiredCursor
The silhouette the in-engine cursor sprite should draw this frame.
DropdownView
What GraphicsSystem needs to draw an open dropdown list: the anchor control rect (reference space), the option labels top-to-bottom, the selected + hovered OPTION indices to highlight, the scroll position (first, the top shown option of a list longer than the layout window), and the row value label’s font / scale / color so the list text matches the row it drops from.
Entities
The entity allocator: slot generations, the free list, and the reservation counter.
Entity
A live entity handle: a slot index plus the generation that slot carried when the handle was minted.
EntityByName
Maps a placement’s asset identity (its declared name) to the live Entity it was loaded into. Built by the decomposition pass so later passes can resolve a name reference (a Prop parent, a PropBody owner, an audio emitter target) to an Entity without scanning.
EventCursor
A reader’s position in an Events queue.
EventStore
Type-keyed event queues, one per event type in use.
Events
A double-buffered event queue: events stay readable for two frames.
ExecutionTrace
What the behavior system observed over one simulated tick, published while a TraceRequest stands. frame increments per published tick so the observer can tell fresh data from the stale resource a paused world leaves behind. events are the nodes that ran (deduplicated); vars the world variables with their current values in slot order; locals the requested entity’s per-behavior locals; hit the first executed breakpoint, if any.
FlyCam
The editor’s fly-camera state. While true (published only by the cn editor HUD drive), InputSystem keeps the navigation keys and mouse deltas live and GraphicsSystem captures the cursor even though the world is frozen behind the editor’s menu override – the editor integrates Camera3D itself, so the viewport can be flown without running the simulation. Absent / false in a shipped runtime.
FrameContext
Frame-scoped facilities a system may use for the duration of its step.
FrameRateCap
The live frame-rate cap in FPS (0 = unlimited), published by GraphicsSystem (from GraphicsConfig at init, refreshed by the settings row’s live change) and read by the App-level frame pacer before each world step. Independent of the quality preset (a user/hardware preference, like vsync).
GpuMemoryPressure
Device-memory pressure signal, published by GraphicsSystem whenever GPU work fails for lack of device memory. Renderer-free counters so the streaming valve can react (tighten budgets, evict) without naming the renderer; nothing consumes it yet.
HiddenAssets
Assets suppressed from rendering for this frame. GraphicsSystem collapses each listed asset’s draw slots to a degenerate transform (so it neither rasterizes nor casts shadows) and drops it from the PickIndex. Authored data is untouched, and the collapse is re-derived every frame, so clearing an id restores the object immediately. Published by the cn editor HUD drive; absent / empty otherwise.
HudLayers
Per-frame draw-layer overrides for HUD Sprites / TextLabels / TextInputs, keyed by asset id and published by the cn editor HUD so its floating panels occlude cleanly. Overlay draw calls render in two passes (all sprites, then all text), so two overlapping panels’ contents merge – one panel’s text draws over the other’s background. GraphicsSystem stable-sorts the overlay calls by this layer (higher draws on top) when the map is non-empty, so the focused panel’s whole content sits above the others’. An id absent from the map is layer 0; an empty / absent resource (the shipped runtime) leaves draw order at insertion order, unchanged.
HudPrefs
Per-frame stats-HUD visibility, published as a resource by GraphicsSystem (which runs first) and read by StatHudSystem the same tick. Each field is the effective on/off for that chip: the master “Display performance stats” toggle AND the per-readout toggle from the video settings. Absent (a HUD-only unit test with no GraphicsSystem) is treated as both shown.
JoinIndex
Entity to component-row index: which components an entity has, and where each one’s row sits in its column.
MenuActive
Per-frame menu state, published as a resource by the overlay build (which runs first in the schedule) and read by the simulation systems the same tick. true while any world-pausing screen is open: physics and animation then freeze so they stop consuming resources behind the menu. Each system keeps its own clock aligned across the freeze, so resuming costs one normal frame – no catch-up burst, no pose jump.
MenuOverride
An external per-frame driver (the cn editor HUD) can force the world’s “menu active” state through this resource: Some(true) frees the cursor and freezes gameplay/physics/animation (edit mode), Some(false) captures the cursor and lets the world run (play mode), both regardless of whether the world has its own menu UI. GraphicsSystem also puts the backend in menu mode while it is set, so a click frees to a UI action instead of re-capturing the camera. None (the default absence) leaves the world’s own menu logic in charge; a shipped runtime never publishes it.
NoPayloads
A payload store holding nothing: every read errors and every release is a no-op. What a World built without a blob runs on – unit tests, and worlds assembled entirely from runtime-only components.
OpenDropdown
A settings dropdown’s open floating option list, or None when none is open. UiInputSystem owns the interaction state (open on a setting:<key>:open click, close on a pick / outside click / Escape / scroll) and publishes this each frame; GraphicsSystem reads it the next tick to draw the list on top of the menu. GraphicsSystem runs first, so the list appears one frame after the row is clicked (the same lag the cursor + cycle labels already carry).
OverlayImage
One extra RGBA8 image for the sprite/text atlas pool, bound to a reserved TextureHandle the inserting tool chose. The handle space must stay clear of the compiled world’s dense texture handles (tools use a high base).
OverlayImages
Extra images appended to the sprite/text atlas pool at graphics init: a sprite whose texture names one of these handles samples the image like any compiled texture. Opt-in like PickIndex: inserted before start (the cn editor HUD injection adds baked asset thumbnails); absent everywhere else, so a shipped runtime never pays for it. Read once at init – images added to the resource later join the pool on the next world rebuild.
PickEntry
One pickable entity in the PickIndex: its asset id and current world-space AABB. Ray-tested by the editor with gfx::pick::ray_aabb.
PickIndex
The per-frame viewport-picking index: every renderable prop entity’s asset id and world-space AABB, refreshed by GraphicsSystem from the live transforms. Opt-in: GraphicsSystem only builds it when the resource is already present at init (the cn editor HUD injection inserts an empty one), so a shipped runtime never pays for it. Rooms, instanced clusters, and voxel chunks are not indexed; picking targets authored prop placements.
PipelineContext
A system’s view of the world for the duration of one step: the five things it borrows, and the accessors that reach them.
Resources
Type-keyed singleton storage: one value per resource type.
ScratchStats
What one frame’s scratch reserve cost and whether it held. A non-zero overflows means some frame fell back to the heap, so peak understates what the frame actually wanted.
ScreenStack
The active screen stack, published by UiInputSystem at init and whenever the stack changes, and read a frame later (the same one-frame lag screen visibility flips already have). layers maps each active Screen’s id to its computed draw layer (authored layer band + stack position; screen-less HUD elements sit at 0); the overlay build spreads these onto the elements each screen owns. pauses_world is true while any active screen pauses the world; captures_input is true while any active screen captures input (gameplay keys are suppressed even when the world keeps simulating). Absent / empty in a world with no active screen.
SimTiming
Fixed-timestep budget for the current frame, published by the App-level simulation clock before each world step. ticks is how many fixed steps the simulation systems (physics, behavior) run this frame; tick_dt is the seconds each step advances; alpha is the accumulator remainder as a fraction of tick_dt, used to blend the previous and current simulated states when writing render-facing transforms. Absent (a directly-stepped world with no App), the default is exactly one tick per step with no blending, which makes bare World::step loops deterministic.
SystemEntry
One row of the system table. Table order is run order.
SystemTable
A host’s system table and the load-time passes only the host can supply.
Tick
A change-detection stamp. Wraps; comparisons use a signed window bounded by MAX_CHANGE_AGE.
TraceEvent
One node execution: which behavior, and the node’s compile-assigned pre-order id (an index into that behavior’s TracePaths entry).
TracePaths
Each behavior’s node paths, indexed by the node ids ExecutionTrace events carry. Published once when tracing is first requested (the compile that derives it runs at init either way; the publish just exposes it).
TraceRequest
An external observer’s request for execution tracing, published per frame by the cn editor HUD while its Behavior panel is open and removed when it closes. While present, the behavior system records which nodes ran each simulated tick and publishes ExecutionTrace; absent (the shipped runtime, or the panel closed), the system does no recording work beyond noticing the absence. entity selects whose per-entity locals to surface; breakpoints are nodes whose execution should be reported as a ExecutionTrace::hit so the observer can pause the simulation.
TransientSaves
Keeps a preview session out of the user’s real save files: while present and true, the systems that persist play state (behavior variables / once flags, story position) neither read nor write their disk saves – every session starts fresh and leaves no trace. In-memory state is unaffected, so a save node still works within the session. Published by the cn editor HUD injection (sampled at each system’s init); a shipped runtime never publishes it.
ViewOverrides
The viewport’s view mode + show flags, published per frame by the editor. GraphicsSystem forwards it to the backend’s FrameParams: the mode selects what the composite presents, the flags skip feature passes for the frame. Absent outside the editor, which reads as the lit default.
World
A world: its component storage, its resources, the compiled payloads it loads from, and the systems that run over all three.
WorldLines
World-space lines to draw this frame (trajectories, tethers, path previews, the editor’s origin axes), republished by their producer every frame: GraphicsSystem expands whatever it finds into ribbon geometry and hands it to the backend, so a stale list would keep drawing. Absent when nothing draws lines, which keeps the line pass out of the frame graph.
WorldPhysicsBudget
The world’s physics reservation as cook counted it, published at blob load. Absent when the world declares no physics content, or when the world was built in memory rather than loaded from a blob; the simulation then counts the loaded components itself.

Enums§

AssetOrigin
Where an asset comes from and whether it persists to a blob.
AssetPayload
Whether the asset has a compiled binary payload packed into a .cnb blob.
ComponentAsset
A loaded component of any registered type.
ComponentTag
The component type tag: one fieldless variant per component, in list order, so each variant’s #[repr(u8)] discriminant is its list position (0, 1, 2, …). ComponentTag::$variant as u8 is that tag, used both as the on-disk blob discriminant and as the in-memory ECS ComponentId. The tag is assigned by position, not hand-written, and is not a stable on-disk contract: a build regenerates the blob, so the blob and the engine that loads it always agree. The authoring RegisteredType registry derives the same tag from this enum.
CursorShape
The silhouette the in-engine cursor sprite should draw this frame. Published by the cn editor HUD when the pointer is over a resizable panel’s edge or corner (or while a resize drag is in flight) and read by the overlay build, which draws the matching shape at the pointer in place of the arrow. Default is the plain arrow; the four resize shapes are double-headed arrows along a window edge (east/west), edge (north/south), and the two diagonals. A shipped runtime never publishes it, so the arrow always stands.
FrameVec
A frame temporary: in the scratch arena when it fit, on the heap when it did not. Reads as &[T] either way, so a caller never branches on which it got.
ScheduleMode
How a tick’s independent work executes. Parallel lets systems fan their safe internal work across the job pool; Serial (or the resource being absent, the editor’s case) keeps every system’s work on the stepping thread – the determinism oracle and the escape hatch (cn run --serial-schedule). Both modes must produce identical world state; the engine’s schedule-determinism test is the gate on that claim.
StepResult
What a system asks the world to do after its step.
TraceStep
One hop of a behavior-node address, mirroring the world checker’s fault paths: object fields by key, list members by position. A node’s path walks from the behavior’s args to the node (e.g. do[1].if.then[0] is [Field("do"), Index(1), Field("if"), Field("then"), Index(0)] minus the node’s own trailing verb), so the editor can resolve a traced node to the same outline row / chart card its checker faults land on. Field names are the fixed authoring keys, so they borrow statically.
TraceVal
A behavior-body value in its cross-boundary form: what Val publishes to an observer. Entities travel as their id bits.

Constants§

HEADLESS_SYSTEMS
The simulation systems a world runs with no host beyond this crate, in run order. What App starts a headless world against.
MAX_CHANGE_AGE
Half the u32 range. A tick older than this relative to the current tick is clamped forward so the signed-window comparison never aliases.

Traits§

BakedMesh
A mesh value a world takes a baked geometry payload for, through World::add_mesh.
Component
Component – pure serializable data, no behavior. The runtime-facing surface only: a component loads from its baked blob bytes and receives its injected identity/payload hooks. All authoring metadata (origin, payload kind, reference fields, args schema, validators) lives in the build-side registry (concinnity-cook), derived from the for_each_component! metadata blocks.
ComponentSlot
Resolves a component type to its column inside the storage at compile time, so the generic storage operations above need no runtime dispatch. A registered component is exactly a type with a $slot impl, and DISCRIMINANT is its stable id, used as its ComponentId in the join index. 'static: components own their data, and the generic ops hand out borrows of (and owned vectors of) the type.
PayloadStore
A source of compiled payload bytes addressed by PayloadLocator.
ResourceAsset
An asset compiled into the blob’s resource stream rather than stored as a component.
RuntimeComponent
A component a world can hold after the cook: every type an authored world declares that survives into a blob, plus every type only the runtime mints.
System
System – has behavior, receives a PipelineContext each tick. Every system is internal engine code: World::start constructs it from world components (via the system’s own new(..)), so a system is never loaded from or written to a blob. init runs once at World::start; step runs every tick.

Type Aliases§

CompleteWorld
A host’s completion pass: it runs over the world before the gates read it, and fails the start when the world cannot be completed.
TracePath
A behavior node’s address: the hops from the behavior’s args down to it.