Core Engine

aether-ecs

Archetype-based Entity Component System

The aether-ecs crate provides Aether's Entity Component System, the foundation that all other engine subsystems build on. It uses archetype-based storage for cache-friendly iteration and supports parallel query execution across multiple systems.

Overview

The ECS follows the classic entity-component-system pattern with a few additions tailored to networked VR applications:

  • Archetype storage groups entities with the same set of components into contiguous memory blocks, maximizing cache locality during iteration.
  • Parallel queries allow multiple read-only systems to execute concurrently on separate threads. Write access is serialized automatically.
  • Network-aware components can be tagged for synchronization, enabling the networking layer to replicate state across clients without manual bookkeeping.
  • Event bus provides a typed, decoupled messaging channel for communication between systems.

Key Types

World

The top-level container for all ECS state. Holds the entity allocator, component storage, and event bus.

use aether_ecs::World;

let mut world = World::new();

Entity

A lightweight identifier (generation + index) referencing an entity in the world.

let entity = world.spawn();
world.despawn(entity);

Component

Any type that implements the Component trait can be attached to an entity. Components are plain data with no behavior.

use aether_ecs::Component;

#[derive(Component)]
struct Position {
    x: f32,
    y: f32,
    z: f32,
}

#[derive(Component)]
struct Velocity {
    x: f32,
    y: f32,
    z: f32,
}

world.insert(entity, Position { x: 0.0, y: 1.0, z: 0.0 });
world.insert(entity, Velocity { x: 1.0, y: 0.0, z: 0.0 });

Query

Queries iterate over entities that match a given component signature. They support read (&T) and write (&mut T) access.

use aether_ecs::Query;

// Iterate over all entities with both Position and Velocity
for (pos, vel) in world.query::<(&mut Position, &Velocity)>() {
    pos.x += vel.x;
    pos.y += vel.y;
    pos.z += vel.z;
}

System

A system is a function that operates on queries. Systems are registered with the world and executed each tick.

use aether_ecs::System;

fn movement_system(query: Query<(&mut Position, &Velocity)>) {
    for (pos, vel) in query.iter() {
        pos.x += vel.x;
        pos.y += vel.y;
        pos.z += vel.z;
    }
}

world.register_system(movement_system);

EventBus

The event bus allows systems to communicate without direct dependencies. Events are typed and consumed each tick.

use aether_ecs::EventBus;

struct CollisionEvent {
    entity_a: Entity,
    entity_b: Entity,
}

// Sending an event
world.events().send(CollisionEvent {
    entity_a: player,
    entity_b: wall,
});

// Reading events in another system
for event in world.events().read::<CollisionEvent>() {
    println!("Collision between {:?} and {:?}", event.entity_a, event.entity_b);
}

Design Highlights

Archetype Storage

When a component is added to or removed from an entity, the entity moves to a different archetype. This keeps entities with the same component set stored contiguously, which results in efficient iteration patterns. The trade-off is that frequent component additions and removals incur a move cost, so structural changes should be batched when possible.

Parallel Queries

The scheduler analyzes system signatures at registration time. Systems that only read overlapping components are scheduled to run in parallel. Systems that write to a component type are serialized with respect to other systems that access the same type. This is handled automatically -- no manual synchronization is required.

Network-Aware Components

Components can be annotated with #[networked] to mark them for replication:

#[derive(Component)]
#[networked(priority = "high", interpolation = "linear")]
struct Transform {
    position: [f32; 3],
    rotation: [f32; 4],
}

The networking layer reads these annotations to determine which components to synchronize, at what priority, and with what interpolation strategy on the client side.