Table of Contents

Class World

Namespace
KeenEyes
Assembly
KeenEyes.Core.dll

The world is the container for all entities and their components. Each world is completely isolated with its own component registry.

public sealed class World : IWorld, IDisposable, ISystemHookCapability, IPersistenceCapability, IHierarchyCapability, IValidationCapability, ITagCapability, IPrefabCapability, IStatisticsCapability, IInspectionCapability, ISerializationCapability, ISnapshotCapability
Inheritance
World
Implements
IWorld
ISystemHookCapability
IPersistenceCapability
IHierarchyCapability
IValidationCapability
ITagCapability
IPrefabCapability
IStatisticsCapability
IInspectionCapability
ISnapshotCapability
Inherited Members

Remarks

World uses an archetype-based storage system for high-performance entity iteration. Entities with the same component types are stored contiguously in memory, enabling cache-friendly access patterns.

The world manages entity lifecycle, component storage, and system execution. Use Spawn() to create entities and Query<T1>() to iterate over entities with specific components.

Constructors

World(int?)

Creates a new ECS world.

public World(int? seed = null)

Parameters

seed int?

Optional seed for the world's random number generator. If null, uses a time-based seed. If specified, enables deterministic behavior for replays and testing.

Examples

// Non-deterministic world (different results each run)
var world1 = new World();

// Deterministic world (same results with same seed)
var world2 = new World(seed: 12345);
var world3 = new World(seed: 12345); // Same sequence as world2

Remarks

Each world has its own isolated random number generator state. Providing a seed ensures that all random operations (via NextInt(int), NextFloat(), etc.) will produce the same sequence of values across runs, enabling deterministic simulations.

Properties

ArchetypeManager

Gets the archetype manager for this world. Provides access to archetype storage, chunk pooling, and entity location tracking.

public ArchetypeManager ArchetypeManager { get; }

Property Value

ArchetypeManager

ArrayPools

Gets the array pool manager for this world. Provides pooled arrays for component storage with per-world statistics tracking.

public ComponentArrayPoolManager ArrayPools { get; }

Property Value

ComponentArrayPoolManager

Components

The component registry for this world. Component IDs are unique per-world, not global.

public ComponentRegistry Components { get; }

Property Value

ComponentRegistry

EntityCount

Gets the total number of entities in the world.

public int EntityCount { get; }

Property Value

int

Events

Gets the event bus for publishing and subscribing to custom events.

public EventBus Events { get; }

Property Value

EventBus

Examples

// Define a custom event
public readonly record struct DamageEvent(Entity Target, int Amount);

// Subscribe
var sub = world.Events.Subscribe<DamageEvent>(e => Console.WriteLine($"Damage: {e.Amount}"));

// Publish
world.Events.Publish(new DamageEvent(entity, 50));

Remarks

The event bus provides a generic pub/sub mechanism for user-defined events. For built-in lifecycle events (entity creation/destruction, component changes), use the dedicated methods like OnEntityCreated(Action<Entity, string?>), OnComponentAdded<T>(Action<Entity, T>), etc.

Id

Unique identifier for this world instance.

public Guid Id { get; }

Property Value

Guid

Remarks

This identifier is useful for distinguishing between multiple worlds in the same process, such as in client-server scenarios or multi-scene games.

Name

Optional name for this world, useful for debugging and logging.

public string? Name { get; set; }

Property Value

string

Remarks

When working with multiple worlds, setting meaningful names like "Client", "Server", or "MainMenu" helps with debugging and tracing issues.

SaveDirectory

Gets or sets the directory where save files are stored.

public string SaveDirectory { get; set; }

Property Value

string

Remarks

Defaults to a "saves" subdirectory in the current working directory.

The directory is created automatically when the first save is performed.

ValidationMode

Gets or sets the validation mode for component constraints.

public ValidationMode ValidationMode { get; set; }

Property Value

ValidationMode

Examples

// Disable validation for maximum performance in production
world.ValidationMode = ValidationMode.Disabled;

// Enable validation only in debug builds
world.ValidationMode = ValidationMode.DebugOnly;

Remarks

Validation checks KeenEyes.RequiresComponentAttribute and KeenEyes.ConflictsWithAttribute constraints when components are added.

Available modes:

  • KeenEyes.ValidationMode.Enabled - Always validate (default)
  • KeenEyes.ValidationMode.Disabled - Skip all validation
  • KeenEyes.ValidationMode.DebugOnly - Only validate in DEBUG builds

Methods

AddChild(Entity, Entity)

Adds a child entity to a parent entity.

public void AddChild(Entity parent, Entity child)

Parameters

parent Entity

The parent entity.

child Entity

The entity to add as a child.

Examples

var parent = world.Spawn().Build();
var child = world.Spawn().Build();

world.AddChild(parent, child);
// Equivalent to: world.SetParent(child, parent);

Remarks

This is a convenience method equivalent to calling SetParent(child, parent).

Exceptions

InvalidOperationException

Thrown when either entity is not alive, or when the relationship would create a circular hierarchy.

See Also

AddSystem(ISystem, SystemPhase, int)

Adds a system instance to this world with specified execution phase and order.

public World AddSystem(ISystem system, SystemPhase phase = SystemPhase.Update, int order = 0)

Parameters

system ISystem

The system instance to add.

phase SystemPhase

The execution phase for this system. Defaults to KeenEyes.SystemPhase.Update.

order int

The execution order within the phase. Lower values execute first. Defaults to 0.

Returns

World

This world for method chaining.

Examples

var customSystem = new CustomSystem("config");
world.AddSystem(customSystem, SystemPhase.Update, order: 10);

Remarks

Use this overload when you need to pass a pre-configured system instance or a system that requires constructor parameters.

Systems are automatically sorted by phase then by order when Update(float) is called.

AddSystem(ISystem, SystemPhase, int, Type[], Type[])

Adds a system instance to this world with specified execution phase, order, and dependency constraints.

public World AddSystem(ISystem system, SystemPhase phase, int order, Type[] runsBefore, Type[] runsAfter)

Parameters

system ISystem

The system instance to add.

phase SystemPhase

The execution phase for this system.

order int

The execution order within the phase. Lower values execute first.

runsBefore Type[]

Types of systems that this system must run before.

runsAfter Type[]

Types of systems that this system must run after.

Returns

World

This world for method chaining.

Examples

var customSystem = new CustomSystem("config");
world.AddSystem(
    customSystem,
    SystemPhase.Update,
    order: 0,
    runsBefore: [typeof(RenderSystem)],
    runsAfter: [typeof(InputSystem)]);

Remarks

Use this overload when you need to pass a pre-configured system instance with explicit ordering constraints.

The runsBefore and runsAfter constraints define explicit ordering dependencies between systems within the same phase. Systems are sorted using topological sorting to respect these constraints.

If constraints create a cycle (e.g., A runs before B, B runs before A), an InvalidOperationException is thrown during the first Update(float) call.

AddSystemHook(SystemHook?, SystemHook?, SystemPhase?)

Adds a global system hook with optional before and after callbacks.

public EventSubscription AddSystemHook(SystemHook? beforeHook = null, SystemHook? afterHook = null, SystemPhase? phase = null)

Parameters

beforeHook SystemHook

Optional callback to invoke before each system execution.

afterHook SystemHook

Optional callback to invoke after each system execution.

phase SystemPhase?

Optional phase filter - hook only executes for systems in this phase.

Returns

EventSubscription

A subscription that can be disposed to unregister the hook.

Examples

// Profiling hook
var profilingHook = world.AddSystemHook(
    beforeHook: (system, dt) => profiler.BeginSystem(system.GetType().Name),
    afterHook: (system, dt) => profiler.EndSystem()
);

// Logging hook (only for Update phase)
var loggingHook = world.AddSystemHook(
    beforeHook: (system, dt) => logger.Debug($"Starting {system.GetType().Name}"),
    afterHook: (system, dt) => logger.Debug($"Finished {system.GetType().Name}"),
    phase: SystemPhase.Update
);

// Conditional execution hook
var debugHook = world.AddSystemHook(
    beforeHook: (system, dt) =>
    {
        if (system is IDebugSystem && !debugMode)
            system.Enabled = false;
    },
    afterHook: null
);

// Later, unregister by disposing
profilingHook.Dispose();
loggingHook.Dispose();
debugHook.Dispose();

Remarks

System hooks enable cross-cutting concerns such as profiling, logging, conditional execution, and metrics collection without modifying individual systems. Hooks are registered globally per-world and execute for all systems (or systems in the specified phase).

Multiple independent hooks can be registered and will execute in registration order. At least one of beforeHook or afterHook must be non-null.

When no hooks are registered, there is minimal performance overhead (empty check only). With hooks registered, overhead scales linearly with the number of hooks.

Exceptions

ArgumentException

Thrown when both beforeHook and afterHook are null.

AddSystem<T>(SystemPhase, int)

Adds a system to this world with specified execution phase and order.

public World AddSystem<T>(SystemPhase phase = SystemPhase.Update, int order = 0) where T : ISystem, new()

Parameters

phase SystemPhase

The execution phase for this system. Defaults to KeenEyes.SystemPhase.Update.

order int

The execution order within the phase. Lower values execute first. Defaults to 0.

Returns

World

This world for method chaining.

Type Parameters

T

The system type to add.

Examples

world.AddSystem<InputSystem>(SystemPhase.EarlyUpdate, order: -10)
     .AddSystem<PhysicsSystem>(SystemPhase.FixedUpdate)
     .AddSystem<MovementSystem>(SystemPhase.Update, order: 0)
     .AddSystem<RenderSystem>(SystemPhase.Render);

Remarks

Systems are automatically sorted by phase then by order when Update(float) is called. Systems in earlier phases (e.g., KeenEyes.SystemPhase.EarlyUpdate) execute before systems in later phases (e.g., KeenEyes.SystemPhase.LateUpdate).

Within the same phase, systems with lower order values execute first. Systems with the same phase and order maintain stable relative ordering.

AddSystem<T>(SystemPhase, int, Type[], Type[])

Adds a system to this world with specified execution phase, order, and dependency constraints.

public World AddSystem<T>(SystemPhase phase, int order, Type[] runsBefore, Type[] runsAfter) where T : ISystem, new()

Parameters

phase SystemPhase

The execution phase for this system.

order int

The execution order within the phase. Lower values execute first.

runsBefore Type[]

Types of systems that this system must run before.

runsAfter Type[]

Types of systems that this system must run after.

Returns

World

This world for method chaining.

Type Parameters

T

The system type to add.

Examples

// MovementSystem must run after InputSystem and before RenderSystem
world.AddSystem<MovementSystem>(
    SystemPhase.Update,
    order: 0,
    runsBefore: [typeof(RenderSystem)],
    runsAfter: [typeof(InputSystem)]);

Remarks

The runsBefore and runsAfter constraints define explicit ordering dependencies between systems within the same phase. Systems are sorted using topological sorting to respect these constraints.

If constraints create a cycle (e.g., A runs before B, B runs before A), an InvalidOperationException is thrown during the first Update(float) call.

AddTag(Entity, string)

Adds a string tag to an entity.

public bool AddTag(Entity entity, string tag)

Parameters

entity Entity

The entity to add the tag to.

tag string

The tag to add. Cannot be null, empty, or whitespace.

Returns

bool

true if the tag was added; false if the entity already had the tag.

Examples

var enemy = world.Spawn()
    .With(new Position { X = 0, Y = 0 })
    .Build();

world.AddTag(enemy, "Enemy");
world.AddTag(enemy, "Hostile");
world.AddTag(enemy, "Boss");

// Check if entity has tag
if (world.HasTag(enemy, "Boss"))
{
    // Special boss handling
}

Remarks

String tags provide runtime-flexible tagging for scenarios like designer-driven content tagging, serialization, and editor tooling. Unlike type-safe tag components (KeenEyes.ITagComponent), string tags can be assigned dynamically without compile-time type definitions.

This operation is O(1).

Exceptions

InvalidOperationException

Thrown when the entity is not alive.

ArgumentNullException

Thrown when tag is null.

ArgumentException

Thrown when tag is empty or whitespace.

See Also

Add<T>(Entity, in T)

Adds a component to an existing entity at runtime.

public void Add<T>(Entity entity, in T component) where T : struct, IComponent

Parameters

entity Entity

The entity to add the component to.

component T

The component value to add.

Type Parameters

T

The component type to add.

Examples

// Create an entity with just Position
var entity = world.Spawn().With(new Position { X = 0, Y = 0 }).Build();

// Later, add Velocity at runtime
world.Add(entity, new Velocity { X = 1, Y = 0 });

// Now entity is matched by queries requiring both Position and Velocity

Remarks

After adding a component, the entity will be matched by queries that require that component type. This operation migrates the entity to a new archetype, which is O(C) where C is the number of components on the entity.

Exceptions

InvalidOperationException

Thrown when the entity is not alive, or when the entity already has a component of the specified type. Use Set<T>(Entity, in T) to update existing components.

Clear()

Clears all entities, components, singletons, and hierarchy data from this world.

public void Clear()

Examples

// Clear world before restoring from snapshot
world.Clear();

// Recreate entities from saved data
foreach (var savedEntity in snapshot.Entities)
{
    world.Spawn(savedEntity.Name)
        .With(savedEntity.Position)
        .Build();
}

Remarks

This method resets the world to an empty state while keeping registered systems, plugins, and event subscriptions intact. It is primarily used for restoring from snapshots where the world state needs to be cleared before recreation.

After clearing, entity IDs start fresh from 0. Any existing entity handles become stale and will return false for IsAlive(Entity).

Note that this method does NOT clear:

  • Registered systems
  • Installed plugins
  • Event subscriptions
  • Extensions
  • The component registry
See Also

ClearAllDirtyFlags()

Clears all dirty flags for all component types.

public void ClearAllDirtyFlags()

Remarks

Use this to reset all tracking state at once, typically at the end of a frame after all change-dependent systems have run.

ClearDirtyFlags<T>()

Clears all dirty flags for a specific component type.

public void ClearDirtyFlags<T>() where T : struct, IComponent

Type Parameters

T

The component type to clear flags for.

Examples

// Process and clear in one pass
foreach (var entity in world.GetDirtyEntities<Position>())
{
    ProcessEntity(entity);
}
world.ClearDirtyFlags<Position>();

Remarks

Call this method after processing dirty entities to reset the tracking state. Typically done at the end of a frame or after synchronization completes.

See Also

ClearQueuedMessages()

Clears all queued messages without processing them.

public void ClearQueuedMessages()

Examples

// Clear all pending messages when resetting level
world.ClearQueuedMessages();

Remarks

Use this to discard pending messages when they are no longer relevant, such as when resetting game state or changing levels.

See Also

ClearQueuedMessages<T>()

Clears queued messages of a specific type without processing them.

public void ClearQueuedMessages<T>()

Type Parameters

T

The message type to clear.

Examples

// Discard all pending collision messages
world.ClearQueuedMessages<CollisionMessage>();
See Also

CopySaveSlot(string, string, bool)

Copies a save slot to a new name.

public SaveSlotInfo CopySaveSlot(string sourceSlotName, string destinationSlotName, bool overwrite = false)

Parameters

sourceSlotName string

The source slot name.

destinationSlotName string

The destination slot name.

overwrite bool

Whether to overwrite if destination exists.

Returns

SaveSlotInfo

The save slot info for the copied slot.

Exceptions

FileNotFoundException

Thrown when the source slot doesn't exist.

IOException

Thrown when destination exists and overwrite is false.

CopySaveSlotAsync(string, string, bool, CancellationToken)

Copies a save slot to a new name asynchronously.

public Task<SaveSlotInfo> CopySaveSlotAsync(string sourceSlotName, string destinationSlotName, bool overwrite = false, CancellationToken cancellationToken = default)

Parameters

sourceSlotName string

The source slot name.

destinationSlotName string

The destination slot name.

overwrite bool

Whether to overwrite if destination exists.

cancellationToken CancellationToken

A cancellation token to cancel the operation.

Returns

Task<SaveSlotInfo>

The save slot info for the copied slot.

DeleteSaveSlot(string)

Deletes a save slot.

public bool DeleteSaveSlot(string slotName)

Parameters

slotName string

The name of the save slot to delete.

Returns

bool

True if the slot was deleted; false if it didn't exist.

DeleteSaveSlotAsync(string, CancellationToken)

Deletes a save slot asynchronously.

public Task<bool> DeleteSaveSlotAsync(string slotName, CancellationToken cancellationToken = default)

Parameters

slotName string

The name of the save slot to delete.

cancellationToken CancellationToken

A cancellation token to cancel the operation.

Returns

Task<bool>

True if the slot was deleted; false if it didn't exist.

Despawn(Entity)

Destroys an entity and all its components.

public bool Despawn(Entity entity)

Parameters

entity Entity

The entity to destroy.

Returns

bool

True if the entity was destroyed, false if it didn't exist.

Remarks

When an entity with children is despawned, its children become orphaned (their parent is set to KeenEyes.Entity.Null). If you want to destroy an entity and all its descendants, use DespawnRecursive(Entity) instead.

When an entity with a parent is despawned, it is automatically removed from its parent's children collection.

See Also

DespawnRecursive(Entity)

Destroys an entity and all its descendants recursively.

public int DespawnRecursive(Entity entity)

Parameters

entity Entity

The entity to destroy along with all its descendants.

Returns

int

The number of entities destroyed (including the root entity and all descendants). Returns 0 if the entity was not alive.

Examples

// Create a hierarchy: root -> child -> grandchild
var root = world.Spawn().Build();
var child = world.Spawn().Build();
var grandchild = world.Spawn().Build();

world.SetParent(child, root);
world.SetParent(grandchild, child);

// Destroy entire hierarchy
int count = world.DespawnRecursive(root);
Debug.Assert(count == 3); // root, child, grandchild
Debug.Assert(!world.IsAlive(root));
Debug.Assert(!world.IsAlive(child));
Debug.Assert(!world.IsAlive(grandchild));

Remarks

This method performs a depth-first traversal to destroy all descendants before destroying the entity itself. This ensures proper cleanup of the hierarchy.

Unlike Despawn(Entity) which orphans children, this method completely removes the entity and its entire subtree from the world.

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns 0 rather than throwing an exception.

This operation is O(N) where N is the total number of entities in the subtree.

See Also

DisableAutoTracking<T>()

Disables automatic dirty tracking for a component type.

public void DisableAutoTracking<T>() where T : struct, IComponent

Type Parameters

T

The component type to disable auto-tracking for.

See Also

DisableSystem<T>()

Disables a system of the specified type.

public bool DisableSystem<T>() where T : class, ISystem

Returns

bool

True if the system was found and disabled; false otherwise.

Type Parameters

T

The type of system to disable.

Examples

// Pause physics simulation
world.DisableSystem<PhysicsSystem>();

Remarks

Disabled systems are skipped during Update(float) calls.

If the system was already disabled, this method has no effect but still returns true.

For systems derived from KeenEyes.SystemBase, the OnDisabled callback is invoked when transitioning from enabled to disabled state.

Dispose()

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

public void Dispose()

EnableAutoTracking<T>()

Enables automatic dirty tracking for a component type.

public void EnableAutoTracking<T>() where T : struct, IComponent

Type Parameters

T

The component type to enable auto-tracking for.

Examples

// Enable auto-tracking for Position
world.EnableAutoTracking<Position>();

// Now Set() calls automatically mark entities dirty
world.Set(entity, new Position { X = 100, Y = 200 });

// The entity is now dirty without manual marking
Debug.Assert(world.IsDirty<Position>(entity));

Remarks

When auto-tracking is enabled, entities are automatically marked dirty when the component is modified via Set<T>(Entity, in T). This saves the need to manually call MarkDirty<T>(Entity) after each Set.

Important: Direct modifications via Get<T>(Entity) references are not automatically tracked, as there is no way to detect when a reference is modified. Use MarkDirty<T>(Entity) manually in those cases.

See Also

EnableSystem<T>()

Enables a system of the specified type.

public bool EnableSystem<T>() where T : class, ISystem

Returns

bool

True if the system was found and enabled; false otherwise.

Type Parameters

T

The type of system to enable.

Examples

// Resume physics simulation
world.EnableSystem<PhysicsSystem>();

Remarks

If the system was already enabled, this method has no effect but still returns true.

For systems derived from KeenEyes.SystemBase, the OnEnabled callback is invoked when transitioning from disabled to enabled state.

FixedUpdate(float)

Updates only systems in the KeenEyes.SystemPhase.FixedUpdate phase.

public void FixedUpdate(float fixedDeltaTime)

Parameters

fixedDeltaTime float

The fixed timestep interval.

Examples

// Typical game loop with fixed timestep
float accumulator = 0f;
const float fixedDeltaTime = 1f / 60f;

while (running)
{
    float frameTime = GetFrameTime();
    accumulator += frameTime;

    while (accumulator >= fixedDeltaTime)
    {
        world.FixedUpdate(fixedDeltaTime);
        accumulator -= fixedDeltaTime;
    }

    world.Update(frameTime);
}

Remarks

This method is intended for fixed-timestep physics and simulation updates that should run at a consistent rate regardless of frame rate. Call this method from your game loop's fixed update tick.

Only systems registered with KeenEyes.SystemPhase.FixedUpdate will be executed. Systems in other phases are not affected by this method.

For systems derived from KeenEyes.SystemBase, the following lifecycle methods are called in order: OnBeforeUpdate, Update, OnAfterUpdate.

GetAllEntities()

Gets all entities currently alive in this world.

public IEnumerable<Entity> GetAllEntities()

Returns

IEnumerable<Entity>

GetAllPrefabNames()

Gets all registered prefab names.

public IEnumerable<string> GetAllPrefabNames()

Returns

IEnumerable<string>

An enumerable of all registered prefab names.

Remarks

The returned names are in no particular order.

GetAllSingletons()

Gets all singletons stored in this world.

public IEnumerable<(Type Type, object Value)> GetAllSingletons()

Returns

IEnumerable<(Type Type, object Value)>

An enumerable of tuples containing each singleton's type and boxed value.

Examples

// Snapshot all singletons for serialization
var singletonSnapshot = world.GetAllSingletons()
    .ToDictionary(s => s.Type.FullName, s => s.Value);

Remarks

This method is primarily intended for serialization and debugging scenarios. Values are boxed, so avoid using this in performance-critical paths.

See Also

GetAncestors(Entity)

Gets all ancestors of an entity (parent, grandparent, etc.).

public IEnumerable<Entity> GetAncestors(Entity entity)

Parameters

entity Entity

The entity to get ancestors for.

Returns

IEnumerable<Entity>

An enumerable of all ancestor entities, starting with the immediate parent and ending with the root. Returns an empty sequence if the entity has no parent or is not alive.

Examples

// Create a hierarchy: root -> child -> grandchild
var root = world.Spawn().Build();
var child = world.Spawn().Build();
var grandchild = world.Spawn().Build();

world.SetParent(child, root);
world.SetParent(grandchild, child);

// GetAncestors(grandchild) returns: child, root
foreach (var ancestor in world.GetAncestors(grandchild))
{
    Console.WriteLine($"Ancestor: {ancestor}");
}

Remarks

This method walks up the hierarchy from the given entity to the root. The entity itself is not included in the results.

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns an empty sequence rather than throwing an exception.

This operation is O(D) where D is the depth of the hierarchy.

See Also

GetChildren(Entity)

Gets all immediate children of an entity.

public IEnumerable<Entity> GetChildren(Entity entity)

Parameters

entity Entity

The entity to get children for.

Returns

IEnumerable<Entity>

An enumerable of child entities. Returns an empty sequence if the entity has no children or is not alive.

Examples

var parent = world.Spawn().Build();
var child1 = world.Spawn().Build();
var child2 = world.Spawn().Build();

world.SetParent(child1, parent);
world.SetParent(child2, parent);

foreach (var child in world.GetChildren(parent))
{
    Console.WriteLine($"Child: {child}");
}

Remarks

This method only returns immediate children, not grandchildren or other descendants. Use GetDescendants(Entity) to get all descendants recursively.

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns an empty sequence rather than throwing an exception.

This operation is O(C) where C is the number of children.

See Also

GetComponents(Entity)

Retrieves all components attached to the specified entity for debugging and introspection.

public IEnumerable<(Type Type, object Value)> GetComponents(Entity entity)

Parameters

entity Entity

The entity to get components from.

Returns

IEnumerable<(Type Type, object Value)>

An enumerable of tuples containing the component type and its boxed value. Returns an empty sequence if the entity is not alive or has no components.

Examples

// Debug: Print all components on an entity
foreach (var (type, value) in world.GetComponents(entity))
{
    Console.WriteLine($"{type.Name}: {value}");
}

// Serialization: Create a snapshot of entity state
var snapshot = world.GetComponents(entity)
    .ToDictionary(c => c.Type.Name, c => c.Value);

Remarks

Boxing overhead: Component values are returned as boxed objects, which incurs allocation costs. This method is intended for debugging, editor integration, and serialization scenarios where performance is not critical. For performance-sensitive code, use Get<T>(Entity) or Has<T>(Entity) instead.

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns an empty sequence rather than throwing an exception.

The complexity is O(C) where C is the number of component types on the entity.

See Also

GetDescendants(Entity)

Gets all descendants of an entity (children, grandchildren, etc.).

public IEnumerable<Entity> GetDescendants(Entity entity)

Parameters

entity Entity

The entity to get descendants for.

Returns

IEnumerable<Entity>

An enumerable of all descendant entities in breadth-first order. Returns an empty sequence if the entity has no descendants or is not alive.

Examples

// Create a hierarchy: root -> child -> grandchild
var root = world.Spawn().Build();
var child = world.Spawn().Build();
var grandchild = world.Spawn().Build();

world.SetParent(child, root);
world.SetParent(grandchild, child);

// GetDescendants returns: child, grandchild
foreach (var descendant in world.GetDescendants(root))
{
    Console.WriteLine($"Descendant: {descendant}");
}

Remarks

This method performs a breadth-first traversal of the hierarchy starting from the given entity. The entity itself is not included in the results.

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns an empty sequence rather than throwing an exception.

This operation is O(N) where N is the total number of descendants.

See Also

GetDirtyCount<T>()

Gets the count of dirty entities for a specific component type.

public int GetDirtyCount<T>() where T : struct, IComponent

Returns

int

The number of entities marked dirty for this component type.

Type Parameters

T

The component type to count.

Remarks

This count may include entities that have been despawned since being marked dirty. Use GetDirtyEntities<T>() to iterate only live entities.

GetDirtyEntities<T>()

Gets all entities that have been marked dirty for a specific component type.

public IEnumerable<Entity> GetDirtyEntities<T>() where T : struct, IComponent

Returns

IEnumerable<Entity>

An enumerable of entities marked dirty for the component type. Returns an empty sequence if no entities are dirty.

Type Parameters

T

The component type to query.

Examples

// Process all entities with modified Position components
foreach (var entity in world.GetDirtyEntities<Position>())
{
    ref readonly var pos = ref world.Get<Position>(entity);
    SyncPositionToNetwork(entity, pos);
}

// Clear after processing
world.ClearDirtyFlags<Position>();

Remarks

The returned entities are verified to be alive. Any entities that were marked dirty but have since been despawned are not included.

This method iterates through all dirty entity IDs and reconstructs full entity handles. For large numbers of dirty entities, consider caching the results if you need to iterate multiple times.

See Also

GetEntityByName(string)

Finds an entity by its assigned name.

public Entity GetEntityByName(string name)

Parameters

name string

The name to search for.

Returns

Entity

The entity with the specified name, or KeenEyes.Entity.Null if no entity with that name exists in this world.

Examples

// Create a named entity
world.Spawn("Player")
    .With(new Position { X = 0, Y = 0 })
    .Build();

// Later, find it by name
var player = world.GetEntityByName("Player");
if (player.IsValid)
{
    ref var pos = ref world.Get<Position>(player);
    Console.WriteLine($"Player at ({pos.X}, {pos.Y})");
}

// Non-existent name returns Entity.Null
var notFound = world.GetEntityByName("NonExistent");
Debug.Assert(!notFound.IsValid);

Remarks

This operation is O(1) for the dictionary-based storage implementation.

Entity names are unique within a world. If you need multiple entities with similar identifiers, consider using a naming convention like "Enemy_01", "Enemy_02", etc.

See Also

GetExtension<T>()

Gets an extension by type.

public T GetExtension<T>() where T : class

Returns

T

The extension instance.

Type Parameters

T

The extension type to retrieve.

Examples

var physics = world.GetExtension<PhysicsWorld>();
var hit = physics.Raycast(origin, direction);

Exceptions

InvalidOperationException

Thrown when no extension of type T exists in this world. Use TryGetExtension<T>(out T) or HasExtension<T>() to check existence before calling this method if the extension may not exist.

GetMemoryStats()

Gets memory usage statistics for this world.

public MemoryStats GetMemoryStats()

Returns

MemoryStats

A snapshot of current memory statistics.

Examples

var stats = world.GetMemoryStats();
Console.WriteLine($"Entities: {stats.EntitiesActive} active");
Console.WriteLine($"Archetypes: {stats.ArchetypeCount}");
Console.WriteLine($"Cache hit rate: {stats.QueryCacheHitRate:F1}%");

Remarks

Statistics are computed on-demand and represent a snapshot in time. They include entity allocations, component storage, and pooling metrics.

GetMessageSubscriberCount<T>()

Gets the number of handlers subscribed to a specific message type.

public int GetMessageSubscriberCount<T>()

Returns

int

The number of subscribed handlers for the message type.

Type Parameters

T

The message type to check.

Remarks

This method is primarily useful for testing and debugging.

GetName(Entity)

Gets the name assigned to an entity, if any.

public string? GetName(Entity entity)

Parameters

entity Entity

The entity to get the name for.

Returns

string

The name assigned to the entity, or null if the entity has no name or is not alive.

Examples

var player = world.Spawn("Player")
    .With(new Position { X = 0, Y = 0 })
    .Build();

var name = world.GetName(player); // Returns "Player"

var unnamed = world.Spawn().Build();
var noName = world.GetName(unnamed); // Returns null

Remarks

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns null rather than throwing an exception.

This operation is O(1) for the dictionary-based storage implementation.

See Also

GetParent(Entity)

Gets the parent of an entity.

public Entity GetParent(Entity entity)

Parameters

entity Entity

The entity to get the parent for.

Returns

Entity

The parent entity, or KeenEyes.Entity.Null if the entity has no parent (is a root entity) or is not alive.

Examples

var parent = world.Spawn().Build();
var child = world.Spawn().Build();
world.SetParent(child, parent);

var foundParent = world.GetParent(child);
Debug.Assert(foundParent == parent);

var rootParent = world.GetParent(parent);
Debug.Assert(!rootParent.IsValid); // Root entities have no parent

Remarks

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns KeenEyes.Entity.Null rather than throwing an exception.

This operation is O(1) for the dictionary-based storage implementation.

See Also

GetPlugin(string)

Gets a plugin by name.

public IWorldPlugin? GetPlugin(string name)

Parameters

name string

The name of the plugin to retrieve.

Returns

IWorldPlugin

The plugin instance, or null if not found.

GetPlugin<T>()

Gets a plugin of the specified type.

public T? GetPlugin<T>() where T : class, IWorldPlugin

Returns

T

The plugin instance, or null if not found.

Type Parameters

T

The plugin type to retrieve.

Examples

var physics = world.GetPlugin<PhysicsPlugin>();
if (physics is not null)
{
    Console.WriteLine($"Physics plugin: {physics.Name}");
}

GetPlugins()

Gets all installed plugins.

public IEnumerable<IWorldPlugin> GetPlugins()

Returns

IEnumerable<IWorldPlugin>

An enumerable of all installed plugins.

GetQueuedMessageCount<T>()

Gets the count of queued messages for a specific type.

public int GetQueuedMessageCount<T>()

Returns

int

The number of queued messages of the specified type.

Type Parameters

T

The message type to check.

Remarks

This method is primarily useful for testing and debugging.

GetRegisteredComponents()

Gets metadata about all registered component types.

public IEnumerable<RegisteredComponentInfo> GetRegisteredComponents()

Returns

IEnumerable<RegisteredComponentInfo>

An enumerable of component metadata.

Remarks

This includes all components that have been registered with the world, whether explicitly or implicitly through entity creation.

GetRoot(Entity)

Gets the root entity of the hierarchy containing the given entity.

public Entity GetRoot(Entity entity)

Parameters

entity Entity

The entity to find the root for.

Returns

Entity

The root entity (the topmost ancestor with no parent). If the entity itself has no parent, returns the entity itself. Returns KeenEyes.Entity.Null if the entity is not alive.

Examples

// Create a hierarchy: root -> child -> grandchild
var root = world.Spawn().Build();
var child = world.Spawn().Build();
var grandchild = world.Spawn().Build();

world.SetParent(child, root);
world.SetParent(grandchild, child);

var foundRoot = world.GetRoot(grandchild);
Debug.Assert(foundRoot == root);

// Root entity returns itself
Debug.Assert(world.GetRoot(root) == root);

Remarks

This method walks up the hierarchy until it finds an entity with no parent. If the given entity has no parent, it is itself the root and is returned.

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns KeenEyes.Entity.Null rather than throwing an exception.

This operation is O(D) where D is the depth of the hierarchy.

See Also

GetSaveSlotInfo(string)

Gets information about a save slot without loading it.

public SaveSlotInfo? GetSaveSlotInfo(string slotName)

Parameters

slotName string

The name of the save slot.

Returns

SaveSlotInfo

The save slot info, or null if the slot doesn't exist.

Examples

var info = world.GetSaveSlotInfo("slot1");
if (info != null)
{
    Console.WriteLine($"Last saved: {info.ModifiedAt}");
    Console.WriteLine($"Play time: {info.PlayTime}");
    Console.WriteLine($"Entities: {info.EntityCount}");
}

Remarks

This is useful for displaying save slot information in a UI without the overhead of loading the full world snapshot.

GetSaveSlotInfoAsync(string, CancellationToken)

Gets information about a save slot without loading it asynchronously.

public Task<SaveSlotInfo?> GetSaveSlotInfoAsync(string slotName, CancellationToken cancellationToken = default)

Parameters

slotName string

The name of the save slot.

cancellationToken CancellationToken

A cancellation token to cancel the operation.

Returns

Task<SaveSlotInfo>

The save slot info, or null if the slot doesn't exist.

GetSaveSlotPath(string)

Gets the file path for a save slot.

public string GetSaveSlotPath(string slotName)

Parameters

slotName string

The slot name.

Returns

string

The full file path where the save would be stored.

GetSingleton<T>()

Gets a singleton value by reference, allowing direct modification.

public ref T GetSingleton<T>() where T : struct

Returns

T

A reference to the singleton data for zero-copy access.

Type Parameters

T

The singleton type to retrieve.

Examples

// Read singleton value
ref readonly var time = ref world.GetSingleton<GameTime>();
float delta = time.DeltaTime;

// Modify singleton directly (zero-copy)
ref var config = ref world.GetSingleton<GameConfig>();
config.Difficulty = 2;

Remarks

This method returns a reference to the boxed singleton value, enabling zero-copy access and direct modification. Changes made through the returned reference are immediately reflected in the stored singleton.

This operation is O(1) for the dictionary-based storage implementation.

Exceptions

InvalidOperationException

Thrown when no singleton of type T exists in this world. Use TryGetSingleton<T>(out T) or HasSingleton<T>() to check existence before calling this method if the singleton may not exist.

See Also

GetSystem<T>()

Gets a system of the specified type from this world.

public T? GetSystem<T>() where T : class, ISystem

Returns

T

The system instance, or null if not found.

Type Parameters

T

The type of system to retrieve.

Examples

var physics = world.GetSystem<PhysicsSystem>();
if (physics is not null)
{
    physics.Enabled = false; // Pause physics
}

Remarks

This method searches for systems by type, including systems nested within KeenEyes.SystemGroup instances.

GetTags(Entity)

Gets all string tags on an entity.

public IReadOnlyCollection<string> GetTags(Entity entity)

Parameters

entity Entity

The entity to get tags for.

Returns

IReadOnlyCollection<string>

A read-only collection of tags on the entity. Returns an empty collection if the entity is not alive or has no tags.

Examples

var tags = world.GetTags(entity);
Console.WriteLine($"Entity has {tags.Count} tags:");
foreach (var tag in tags)
{
    Console.WriteLine($"  - {tag}");
}

Remarks

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns an empty collection rather than throwing an exception.

This operation is O(1) to obtain the collection.

See Also

GetTotalQueuedMessageCount()

Gets the total count of all queued messages across all types.

public int GetTotalQueuedMessageCount()

Returns

int

The total number of queued messages.

Remarks

This method is primarily useful for testing and debugging.

Get<T>(Entity)

Gets a component from an entity by reference, allowing direct modification.

public ref T Get<T>(Entity entity) where T : struct, IComponent

Parameters

entity Entity

The entity to get the component from.

Returns

T

A reference to the component data for zero-copy access.

Type Parameters

T

The component type to retrieve.

Examples

ref var position = ref world.Get<Position>(entity);
position.X += 10; // Modifies the component directly

Exceptions

InvalidOperationException

Thrown when the entity is not alive, the component type is not registered, or the entity does not have the specified component.

HasComponent(Entity, Type)

Checks if an entity has a component of the specified runtime type.

public bool HasComponent(Entity entity, Type componentType)

Parameters

entity Entity

The entity to check.

componentType Type

The component type to check for.

Returns

bool

true if the entity has the component; false otherwise.

Remarks

This method is useful when the component type is only known at runtime, such as during validation or reflection-based operations.

If the entity is no longer alive (stale handle) or the component type is not registered, this method returns false.

HasExtension<T>()

Checks if an extension of the specified type exists.

public bool HasExtension<T>() where T : class

Returns

bool

True if the extension exists; false otherwise.

Type Parameters

T

The extension type to check for.

HasMessageSubscribers<T>()

Checks if there are any handlers subscribed to a specific message type.

public bool HasMessageSubscribers<T>()

Returns

bool

true if at least one handler is subscribed; otherwise, false.

Type Parameters

T

The message type to check.

Examples

// Skip creating expensive message data if no one is listening
if (world.HasMessageSubscribers<ExpensiveMessage>())
{
    var messageData = CreateExpensiveMessageData();
    world.Send(messageData);
}

Remarks

This can be used to skip expensive message creation when no handlers are listening.

See Also

HasPlugin(string)

Checks if a plugin with the specified name is installed.

public bool HasPlugin(string name)

Parameters

name string

The name of the plugin to check for.

Returns

bool

True if the plugin is installed; false otherwise.

HasPlugin<T>()

Checks if a plugin of the specified type is installed.

public bool HasPlugin<T>() where T : IWorldPlugin

Returns

bool

True if the plugin is installed; false otherwise.

Type Parameters

T

The plugin type to check for.

HasPrefab(string)

Checks if a prefab with the given name is registered.

public bool HasPrefab(string name)

Parameters

name string

The name to check.

Returns

bool

true if a prefab with the name exists; otherwise, false.

Examples

if (world.HasPrefab("Enemy"))
{
    var enemy = world.SpawnFromPrefab("Enemy").Build();
}

Exceptions

ArgumentNullException

Thrown when name is null.

HasSingleton<T>()

Checks if a singleton of the specified type exists in this world.

public bool HasSingleton<T>() where T : struct

Returns

bool

true if a singleton of type T exists; false otherwise.

Type Parameters

T

The singleton type to check for.

Examples

if (world.HasSingleton<GameTime>())
{
    ref var time = ref world.GetSingleton<GameTime>();
    // Use time...
}

Remarks

This method provides a quick way to check singleton existence without retrieving the value or risking exceptions.

This operation is O(1) for the dictionary-based storage implementation.

See Also

HasTag(Entity, string)

Checks if an entity has a specific string tag.

public bool HasTag(Entity entity, string tag)

Parameters

entity Entity

The entity to check.

tag string

The tag to check for. Cannot be null, empty, or whitespace.

Returns

bool

true if the entity is alive and has the specified tag; false if the entity is not alive or doesn't have the tag.

Examples

foreach (var entity in world.Query<Position>())
{
    if (world.HasTag(entity, "Player"))
    {
        // Handle player entity
    }
}

Remarks

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns false rather than throwing an exception.

This operation is O(1).

Exceptions

ArgumentNullException

Thrown when tag is null.

ArgumentException

Thrown when tag is empty or whitespace.

See Also

Has<T>(Entity)

Checks if an entity has a specific component type.

public bool Has<T>(Entity entity) where T : struct, IComponent

Parameters

entity Entity

The entity to check.

Returns

bool

true if the entity is alive and has the specified component; false if the entity is not alive, the component type is not registered, or the entity does not have the component.

Type Parameters

T

The component type to check for.

Examples

// Conditional component access
if (world.Has<Velocity>(entity))
{
    ref var velocity = ref world.Get<Velocity>(entity);
    // Process velocity...
}

// Guard clause pattern
if (!world.Has<Health>(entity))
{
    return; // Skip entities without health
}

Remarks

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns false rather than throwing an exception.

This operation is O(1) for the archetype-based storage implementation.

Use this method to conditionally check for components before calling Get<T>(Entity) to avoid exceptions, or use the guard clause pattern to skip entities that lack required components.

See Also

InstallPlugin(IWorldPlugin)

Installs a plugin instance into this world.

public World InstallPlugin(IWorldPlugin plugin)

Parameters

plugin IWorldPlugin

The plugin instance to install.

Returns

World

This world for method chaining.

Examples

var physics = new PhysicsPlugin(gravity: -9.81f);
world.InstallPlugin(physics);

Remarks

Use this overload when you need to pass a pre-configured plugin instance.

Exceptions

ArgumentNullException

Thrown when plugin is null.

InvalidOperationException

Thrown when a plugin with the same name is already installed.

InstallPlugin<T>()

Installs a plugin into this world.

public World InstallPlugin<T>() where T : IWorldPlugin, new()

Returns

World

This world for method chaining.

Type Parameters

T

The plugin type to install.

Examples

world.InstallPlugin<PhysicsPlugin>()
     .InstallPlugin<RenderingPlugin>();

Remarks

The plugin's KeenEyes.IWorldPlugin.Install(KeenEyes.IPluginContext) method is called during installation. Systems registered by the plugin are tracked and will be automatically removed when the plugin is uninstalled.

Exceptions

InvalidOperationException

Thrown when a plugin with the same name is already installed.

IsAlive(Entity)

Checks if an entity is still alive.

public bool IsAlive(Entity entity)

Parameters

entity Entity

Returns

bool

IsAutoTrackingEnabled<T>()

Checks if automatic dirty tracking is enabled for a component type.

public bool IsAutoTrackingEnabled<T>() where T : struct, IComponent

Returns

bool

true if auto-tracking is enabled; false otherwise.

Type Parameters

T

The component type to check.

IsDirty<T>(Entity)

Checks if an entity is marked dirty for a specific component type.

public bool IsDirty<T>(Entity entity) where T : struct, IComponent

Parameters

entity Entity

The entity to check.

Returns

bool

true if the entity is marked dirty for the component type; false if not dirty or the entity is not alive.

Type Parameters

T

The component type to check.

Examples

if (world.IsDirty<Position>(entity))
{
    // Entity's position has been modified since last clear
    SyncPosition(entity);
}

Remarks

This method is safe to call with stale entity handles. A stale handle refers to an entity that has been destroyed (via Despawn(Entity)). In such cases, this method returns false rather than throwing an exception.

ListSaveSlots()

Lists all available save slots.

public IEnumerable<SaveSlotInfo> ListSaveSlots()

Returns

IEnumerable<SaveSlotInfo>

An enumerable of save slot info for all valid save files.

Examples

foreach (var slot in world.ListSaveSlots())
{
    Console.WriteLine($"{slot.SlotName}: {slot.DisplayName ?? slot.SlotName}");
    Console.WriteLine($"  Modified: {slot.ModifiedAt}");
    Console.WriteLine($"  Play time: {slot.PlayTime}");
}

Remarks

Invalid or corrupted save files are silently skipped.

ListSaveSlotsAsync(CancellationToken)

Lists all available save slots asynchronously.

public Task<IReadOnlyList<SaveSlotInfo>> ListSaveSlotsAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A cancellation token to cancel the operation.

Returns

Task<IReadOnlyList<SaveSlotInfo>>

A list of save slot info for all valid save files.

LoadFromSlotAsync<TSerializer>(string, TSerializer, bool, CancellationToken)

Loads a world state from a save slot asynchronously.

public Task<(SaveSlotInfo SlotInfo, Dictionary<int, Entity> EntityMap)> LoadFromSlotAsync<TSerializer>(string slotName, TSerializer serializer, bool validateChecksum = true, CancellationToken cancellationToken = default) where TSerializer : IComponentSerializer, IBinaryComponentSerializer

Parameters

slotName string

The name of the save slot to load.

serializer TSerializer

The component serializer for AOT-compatible deserialization.

validateChecksum bool

Whether to validate the checksum if present. Defaults to true.

cancellationToken CancellationToken

A cancellation token to cancel the operation.

Returns

Task<(SaveSlotInfo SlotInfo, Dictionary<int, Entity> EntityMap)>

A tuple containing the save slot info and a mapping from original entity IDs to new entities.

Type Parameters

TSerializer

The serializer type that implements both IComponentSerializer and IBinaryComponentSerializer.

Remarks

This async version performs file I/O without blocking the calling thread.

Note that snapshot deserialization and world restoration are still synchronous CPU-bound operations. Only the file I/O is performed asynchronously.

LoadFromSlot<TSerializer>(string, TSerializer, bool)

Loads a world state from a save slot.

public (SaveSlotInfo SlotInfo, Dictionary<int, Entity> EntityMap) LoadFromSlot<TSerializer>(string slotName, TSerializer serializer, bool validateChecksum = true) where TSerializer : IComponentSerializer, IBinaryComponentSerializer

Parameters

slotName string

The name of the save slot to load.

serializer TSerializer

The component serializer for AOT-compatible deserialization. Pass the generated ComponentSerializer from your project.

validateChecksum bool

Whether to validate the checksum if present. Defaults to true.

Returns

(SaveSlotInfo SlotInfo, Dictionary<int, Entity> EntityMap)

A tuple containing the save slot info and a mapping from original entity IDs to new entities.

Type Parameters

TSerializer

The serializer type that implements both IComponentSerializer and IBinaryComponentSerializer.

Examples

var (info, entityMap) = world.LoadFromSlot("slot1", serializer);

// Use entityMap to find restored entities by their original IDs
if (entityMap.TryGetValue(originalPlayerId, out var player))
{
    // player is the restored entity
}

Remarks

Loading a slot clears the current world state before restoring the saved state. Entity IDs in the restored world may differ from the original saved IDs. Use the returned entity map to translate original IDs to new entities.

Exceptions

FileNotFoundException

Thrown when the save slot doesn't exist.

InvalidDataException

Thrown when the save file is corrupted.

MarkDirty<T>(Entity)

Manually marks an entity as dirty (modified) for a specific component type.

public void MarkDirty<T>(Entity entity) where T : struct, IComponent

Parameters

entity Entity

The entity to mark as dirty.

Type Parameters

T

The component type to mark as dirty.

Examples

// Modify a component via Get and manually mark dirty
ref var position = ref world.Get<Position>(entity);
position.X += 10;
world.MarkDirty<Position>(entity);

// Later, process dirty entities
foreach (var dirtyEntity in world.GetDirtyEntities<Position>())
{
    SyncToNetwork(dirtyEntity);
}
world.ClearDirtyFlags<Position>();

Remarks

Use this method to flag entities for change-based processing when modifying components via Get<T>(Entity) references. Modifications through Set<T>(Entity, in T) can be automatically tracked if EnableAutoTracking<T>() has been called.

This method is idempotent: marking an already-dirty entity has no additional effect.

Exceptions

InvalidOperationException

Thrown when the entity is not alive.

See Also

NextBool()

Gets a random boolean value.

public bool NextBool()

Returns

bool

True or false with equal probability.

Examples

// Randomly choose between two options
if (world.NextBool())
{
    entity.WithGravity(9.8f);
}

NextBool(float)

Returns a random boolean with the specified probability of being true.

public bool NextBool(float probability)

Parameters

probability float

The probability (0.0 to 1.0) that the result will be true.

Returns

bool

True with the specified probability, false otherwise.

Examples

// 30% chance of gravity
if (world.NextBool(0.3f))
{
    entity.WithGravity(9.8f);
}

Exceptions

ArgumentOutOfRangeException

probability is less than 0.0 or greater than 1.0.

NextDouble()

Gets a random double-precision floating-point number between 0.0 (inclusive) and 1.0 (exclusive).

public double NextDouble()

Returns

double

A double-precision floating point number greater than or equal to 0.0, and less than 1.0.

NextFloat()

Gets a random floating-point number between 0.0 (inclusive) and 1.0 (exclusive).

public float NextFloat()

Returns

float

A single-precision floating point number greater than or equal to 0.0, and less than 1.0.

Examples

// 30% chance of gravity
bool hasGravity = world.NextFloat() < 0.3f;

// Random position in world
float x = world.NextFloat() * worldWidth;
float y = world.NextFloat() * worldHeight;

NextInt(int)

Gets a random integer between 0 (inclusive) and maxValue (exclusive).

public int NextInt(int maxValue)

Parameters

maxValue int

The exclusive upper bound of the random number to be generated.

Returns

int

A 32-bit signed integer greater than or equal to 0, and less than maxValue.

Examples

// Spawn enemy at random edge (0-3)
int edge = world.NextInt(4);

Remarks

Uses the world's deterministic random number generator. If the world was created with a seed, this method will produce the same sequence of values across runs.

Each world has its own isolated RNG state, ensuring deterministic behavior for replays and testing.

Exceptions

ArgumentOutOfRangeException

maxValue is less than 0.

NextInt(int, int)

Gets a random integer between minValue (inclusive) and maxValue (exclusive).

public int NextInt(int minValue, int maxValue)

Parameters

minValue int

The inclusive lower bound of the random number returned.

maxValue int

The exclusive upper bound of the random number returned.

Returns

int

A 32-bit signed integer greater than or equal to minValue and less than maxValue.

Examples

// Random velocity between -10 and 10
int velocity = world.NextInt(-10, 11);

Exceptions

ArgumentOutOfRangeException

minValue is greater than maxValue.

OnComponentAdded<T>(Action<Entity, T>)

Registers a handler to be called when a component of type T is added to an entity.

public EventSubscription OnComponentAdded<T>(Action<Entity, T> handler) where T : struct, IComponent

Parameters

handler Action<Entity, T>

The handler to invoke when the component is added. Receives the entity and the component value that was added.

Returns

EventSubscription

An KeenEyes.EventSubscription that can be disposed to unsubscribe the handler.

Type Parameters

T

The component type to watch for additions.

Examples

var subscription = world.OnComponentAdded<Health>((entity, health) =>
{
    Console.WriteLine($"Entity {entity} now has {health.Current}/{health.Max} health");
});

// Later, unsubscribe
subscription.Dispose();

Remarks

This event fires after the component has been successfully added to the entity. The entity is guaranteed to have the component when the handler is invoked.

Component additions occur when calling Add<T>(Entity, in T) at runtime or when building an entity with With<T>(T).

See Also

OnComponentChanged<T>(Action<Entity, T, T>)

Registers a handler to be called when a component of type T is changed on an entity via Set<T>(Entity, in T).

public EventSubscription OnComponentChanged<T>(Action<Entity, T, T> handler) where T : struct, IComponent

Parameters

handler Action<Entity, T, T>

The handler to invoke when the component is changed. Receives the entity, the old component value, and the new component value.

Returns

EventSubscription

An KeenEyes.EventSubscription that can be disposed to unsubscribe the handler.

Type Parameters

T

The component type to watch for changes.

Examples

var subscription = world.OnComponentChanged<Health>((entity, oldHealth, newHealth) =>
{
    if (newHealth.Current <= 0 && oldHealth.Current > 0)
    {
        Console.WriteLine($"Entity {entity} just died!");
    }
});

Remarks

This event is only fired when using Set<T>(Entity, in T). Direct modifications via Get<T>(Entity) references do not trigger this event since there is no way to detect when a reference is modified.

This is useful for implementing reactive patterns where systems need to respond to specific component value changes, such as health dropping to zero.

See Also

OnComponentRemoved<T>(Action<Entity>)

Registers a handler to be called when a component of type T is removed from an entity.

public EventSubscription OnComponentRemoved<T>(Action<Entity> handler) where T : struct, IComponent

Parameters

handler Action<Entity>

The handler to invoke when the component is removed.

Returns

EventSubscription

An KeenEyes.EventSubscription that can be disposed to unsubscribe the handler.

Type Parameters

T

The component type to watch for removals.

Examples

var subscription = world.OnComponentRemoved<Health>(entity =>
{
    Console.WriteLine($"Entity {entity} lost its Health component");
});

Remarks

This event fires before the component is fully removed. The handler receives only the entity, not the component value, because the component data may be in the process of being overwritten.

Component removals occur when calling Remove<T>(Entity) or when despawning an entity.

See Also

OnEntityCreated(Action<Entity, string?>)

Registers a handler to be called when an entity is created.

public EventSubscription OnEntityCreated(Action<Entity, string?> handler)

Parameters

handler Action<Entity, string>

The handler to invoke when an entity is created. Receives the entity and its optional name (null if unnamed).

Returns

EventSubscription

An KeenEyes.EventSubscription that can be disposed to unsubscribe the handler.

Examples

var subscription = world.OnEntityCreated((entity, name) =>
{
    if (name is not null)
    {
        Console.WriteLine($"Named entity created: {name}");
    }
    else
    {
        Console.WriteLine($"Anonymous entity created: {entity}");
    }
});

Remarks

This event fires after the entity has been fully created and added to the world, including all initial components from the entity builder.

Entity creation events occur when Build() is called.

See Also

OnEntityDestroyed(Action<Entity>)

Registers a handler to be called when an entity is destroyed.

public EventSubscription OnEntityDestroyed(Action<Entity> handler)

Parameters

handler Action<Entity>

The handler to invoke when an entity is destroyed.

Returns

EventSubscription

An KeenEyes.EventSubscription that can be disposed to unsubscribe the handler.

Examples

var subscription = world.OnEntityDestroyed(entity =>
{
    var name = world.GetName(entity);
    Console.WriteLine($"Entity destroyed: {name ?? entity.ToString()}");
});

Remarks

This event fires at the start of the despawn process, before the entity is removed from the world. The entity handle is still valid during the callback and can be used to query components.

Entity destruction events occur when Despawn(Entity) or DespawnRecursive(Entity) is called.

See Also

PreallocateArchetypeFor<TBundle>(int)

Pre-allocates an archetype for all components in the specified bundle type.

public void PreallocateArchetypeFor<TBundle>(int initialCapacity = 16) where TBundle : struct, IBundle

Parameters

initialCapacity int

Initial capacity for entity storage. Defaults to 16.

Type Parameters

TBundle

The bundle type.

Examples

// Pre-allocate for a custom bundle
world.PreallocateArchetypeFor<TransformBundle>();

// Now spawning entities with this bundle is optimized
for (int i = 0; i < 1000; i++)
{
    var entity = world.Spawn()
        .With(new TransformBundle(...))
        .Build();
}

Remarks

This method uses the static abstract KeenEyes.IBundle.ComponentTypes member for AOT-compatible access to bundle component types without reflection.

For better performance, bundles are automatically pre-allocated during World initialization. Use this method when you want to pre-allocate a bundle archetype after World creation.

PreallocateArchetype<T1>(int)

Pre-allocates an archetype for the specified component types.

public void PreallocateArchetype<T1>(int initialCapacity = 16) where T1 : struct, IComponent

Parameters

initialCapacity int

Initial capacity for entity storage. Defaults to 16.

Type Parameters

T1

The first component type.

Examples

world.PreallocateArchetype<Position>();

// Now spawning entities with Position is optimized
for (int i = 0; i < 1000; i++)
{
    var entity = world.Spawn().With(new Position { X = i, Y = i }).Build();
}

Remarks

Pre-allocating archetypes can reduce the number of archetype transitions when spawning many entities with the same component set. This is particularly useful when used with bundles.

If an archetype with these component types already exists, this method returns immediately without creating a new archetype.

PreallocateArchetype<T1, T2>(int)

Pre-allocates an archetype for the specified component types.

public void PreallocateArchetype<T1, T2>(int initialCapacity = 16) where T1 : struct, IComponent where T2 : struct, IComponent

Parameters

initialCapacity int

Initial capacity for entity storage. Defaults to 16.

Type Parameters

T1

The first component type.

T2

The second component type.

Remarks

Pre-allocating archetypes can reduce the number of archetype transitions when spawning many entities with the same component set. This is particularly useful when used with bundles.

If an archetype with these component types already exists, this method returns immediately without creating a new archetype.

PreallocateArchetype<T1, T2, T3>(int)

Pre-allocates an archetype for the specified component types.

public void PreallocateArchetype<T1, T2, T3>(int initialCapacity = 16) where T1 : struct, IComponent where T2 : struct, IComponent where T3 : struct, IComponent

Parameters

initialCapacity int

Initial capacity for entity storage. Defaults to 16.

Type Parameters

T1

The first component type.

T2

The second component type.

T3

The third component type.

Remarks

Pre-allocating archetypes can reduce the number of archetype transitions when spawning many entities with the same component set. This is particularly useful when used with bundles.

If an archetype with these component types already exists, this method returns immediately without creating a new archetype.

PreallocateArchetype<T1, T2, T3, T4>(int)

Pre-allocates an archetype for the specified component types.

public void PreallocateArchetype<T1, T2, T3, T4>(int initialCapacity = 16) where T1 : struct, IComponent where T2 : struct, IComponent where T3 : struct, IComponent where T4 : struct, IComponent

Parameters

initialCapacity int

Initial capacity for entity storage. Defaults to 16.

Type Parameters

T1

The first component type.

T2

The second component type.

T3

The third component type.

T4

The fourth component type.

Remarks

Pre-allocating archetypes can reduce the number of archetype transitions when spawning many entities with the same component set. This is particularly useful when used with bundles.

If an archetype with these component types already exists, this method returns immediately without creating a new archetype.

ProcessQueuedMessages()

Processes all queued messages, delivering them to subscribed handlers.

public void ProcessQueuedMessages()

Examples

// In your game loop, process queued messages at a specific point
world.Update(deltaTime);
world.ProcessQueuedMessages(); // Process all messages queued during Update

Remarks

Messages are processed in FIFO order within each message type. The order in which different message types are processed is not guaranteed.

After processing, all message queues are cleared. If a handler throws an exception, the exception propagates and remaining messages may not be processed.

See Also

ProcessQueuedMessages<T>()

Processes all queued messages of a specific type.

public void ProcessQueuedMessages<T>()

Type Parameters

T

The message type to process.

Examples

// Process only damage messages at this point
world.ProcessQueuedMessages<DamageMessage>();

// Physics messages are processed later
world.ProcessQueuedMessages<CollisionMessage>();

Remarks

Only processes messages of the specified type. Other queued messages remain queued. This is useful when you need fine-grained control over when specific message types are processed.

See Also

QueryByTag(string)

Gets all entities that have a specific string tag.

public IEnumerable<Entity> QueryByTag(string tag)

Parameters

tag string

The tag to query for. Cannot be null, empty, or whitespace.

Returns

IEnumerable<Entity>

An enumerable of entities that have the specified tag. Returns an empty sequence if no entities have the tag.

Examples

// Process all enemies
foreach (var entity in world.QueryByTag("Enemy"))
{
    ref var pos = ref world.Get<Position>(entity);
    // Update enemy position
}

// Count players
var playerCount = world.QueryByTag("Player").Count();

Remarks

This method filters out any stale entity references, ensuring all returned entities are alive.

This operation is O(N) where N is the number of entities with the tag.

Exceptions

ArgumentNullException

Thrown when tag is null.

ArgumentException

Thrown when tag is empty or whitespace.

See Also

Query<T1>()

Creates a query for entities with the specified component.

public QueryBuilder Query<T1>() where T1 : struct, IComponent

Returns

QueryBuilder

Type Parameters

T1

Query<T1, T2>()

Creates a query for entities with the specified components.

public QueryBuilder Query<T1, T2>() where T1 : struct, IComponent where T2 : struct, IComponent

Returns

QueryBuilder

Type Parameters

T1
T2

Query<T1, T2, T3>()

Creates a query for entities with the specified components.

public QueryBuilder Query<T1, T2, T3>() where T1 : struct, IComponent where T2 : struct, IComponent where T3 : struct, IComponent

Returns

QueryBuilder

Type Parameters

T1
T2
T3

Query<T1, T2, T3, T4>()

Creates a query for entities with the specified components.

public QueryBuilder Query<T1, T2, T3, T4>() where T1 : struct, IComponent where T2 : struct, IComponent where T3 : struct, IComponent where T4 : struct, IComponent

Returns

QueryBuilder

Type Parameters

T1
T2
T3
T4

QueueMessage<T>(in T)

Queues a message for deferred delivery.

public void QueueMessage<T>(in T message)

Parameters

message T

The message data to queue.

Type Parameters

T

The message type to queue.

Examples

// Queue messages during system updates
foreach (var entity in world.Query<Collision>())
{
    world.QueueMessage(new CollisionMessage(entity, other));
}

// Process all queued messages at a specific point
world.ProcessQueuedMessages();

Remarks

Queued messages are stored and delivered when ProcessQueuedMessages() is called. This is useful when you want to collect messages during a system's update and process them all at once, or when you want to ensure messages are processed at a specific point in the update cycle.

Messages are processed in FIFO order (first-in, first-out) within each message type.

See Also

RegisterPrefab(string, EntityPrefab)

Registers a prefab with the given name for later instantiation.

public void RegisterPrefab(string name, EntityPrefab prefab)

Parameters

name string

The unique name for the prefab.

prefab EntityPrefab

The prefab definition to register.

Examples

// Define a base enemy prefab
var enemyPrefab = new EntityPrefab()
    .With(new Health { Current = 100, Max = 100 })
    .With(new Position { X = 0, Y = 0 })
    .WithTag<EnemyTag>();

world.RegisterPrefab("Enemy", enemyPrefab);

// Create entities from the prefab
var enemy1 = world.SpawnFromPrefab("Enemy").Build();
var enemy2 = world.SpawnFromPrefab("Enemy").Build();

Remarks

Prefabs are reusable entity templates that define a set of components. Once registered, entities can be created from the prefab using SpawnFromPrefab(string).

Prefabs support inheritance through Extends(string). When spawning from a derived prefab, the inheritance chain is resolved and components are merged, with derived prefabs overriding base prefab components of the same type.

Exceptions

ArgumentNullException

Thrown when name or prefab is null.

ArgumentException

Thrown when a prefab with the given name is already registered.

See Also

RegisterValidator<T>(ComponentValidator<T>)

Registers a custom validator for a component type.

public void RegisterValidator<T>(ComponentValidator<T> validator) where T : struct, IComponent

Parameters

validator ComponentValidator<T>

A delegate that receives the world, entity, and component data, and returns true if validation passes.

Type Parameters

T

The component type to validate.

Examples

// Validate that Health.Current never exceeds Health.Max
world.RegisterValidator<Health>((world, entity, health) =>
    health.Current >= 0 && health.Current <= health.Max && health.Max > 0);

// This will throw ComponentValidationException:
world.Add(entity, new Health { Current = 150, Max = 100 });

Remarks

Custom validators run in addition to attribute-based validation (KeenEyes.RequiresComponentAttribute and KeenEyes.ConflictsWithAttribute).

The validator is called when the component is added via Add<T>(Entity, in T) or during entity creation via Build().

Exceptions

ArgumentNullException

Thrown when validator is null.

RemoveChild(Entity, Entity)

Removes a specific child from a parent entity.

public bool RemoveChild(Entity parent, Entity child)

Parameters

parent Entity

The parent entity.

child Entity

The child entity to remove from the parent.

Returns

bool

true if the child was removed from the parent; false if the parent is not alive, the child is not alive, or the child was not a child of the parent.

Examples

var parent = world.Spawn().Build();
var child = world.Spawn().Build();

world.SetParent(child, parent);
bool removed = world.RemoveChild(parent, child);
Debug.Assert(removed);
Debug.Assert(!world.GetParent(child).IsValid); // Child is now a root

Remarks

After removal, the child becomes a root entity (has no parent).

This operation is idempotent: calling it multiple times with the same arguments will return false after the first successful removal.

See Also

RemoveExtension<T>()

Removes an extension from this world.

public bool RemoveExtension<T>() where T : class

Returns

bool

True if the extension was found and removed; false otherwise.

Type Parameters

T

The extension type to remove.

RemoveSingleton<T>()

Removes a singleton from this world.

public bool RemoveSingleton<T>() where T : struct

Returns

bool

true if the singleton was removed; false if no singleton of type T existed.

Type Parameters

T

The singleton type to remove.

Examples

// Remove a singleton
bool removed = world.RemoveSingleton<GameTime>();
if (removed)
{
    Console.WriteLine("GameTime singleton removed");
}

// Idempotent: second removal returns false
bool removedAgain = world.RemoveSingleton<GameTime>();
Debug.Assert(removedAgain == false);

Remarks

This operation is idempotent: calling it multiple times with the same type will return false after the first successful removal.

This operation is O(1) for the dictionary-based storage implementation.

See Also

RemoveTag(Entity, string)

Removes a string tag from an entity.

public bool RemoveTag(Entity entity, string tag)

Parameters

entity Entity

The entity to remove the tag from.

tag string

The tag to remove. Cannot be null, empty, or whitespace.

Returns

bool

true if the tag was removed; false if the entity didn't have the tag.

Examples

// Remove a tag when enemy becomes friendly
world.RemoveTag(entity, "Hostile");
world.AddTag(entity, "Friendly");

Remarks

This operation is O(1).

Exceptions

InvalidOperationException

Thrown when the entity is not alive.

ArgumentNullException

Thrown when tag is null.

ArgumentException

Thrown when tag is empty or whitespace.

See Also

Remove<T>(Entity)

Removes a component from an entity.

public bool Remove<T>(Entity entity) where T : struct, IComponent

Parameters

entity Entity

The entity to remove the component from.

Returns

bool

true if the component was removed; false if the entity is not alive, the component type is not registered, or the entity does not have the component.

Type Parameters

T

The component type to remove.

Examples

// Remove a component from an entity
bool removed = world.Remove<Velocity>(entity);
if (removed)
{
    Console.WriteLine("Velocity component removed");
}

// Idempotent: second removal returns false
bool removedAgain = world.Remove<Velocity>(entity);
Debug.Assert(removedAgain == false);

Remarks

This operation is idempotent: calling it multiple times with the same arguments will return false after the first successful removal.

After removing a component, the entity will no longer be matched by queries that require that component type. This operation migrates the entity to a new archetype.

Warning: Removing components from entities during query iteration may cause unexpected behavior. Consider using a command buffer pattern where removals are queued and applied after iteration completes.

RenameSaveSlot(string, string)

Renames a save slot.

public SaveSlotInfo RenameSaveSlot(string oldSlotName, string newSlotName)

Parameters

oldSlotName string

The current slot name.

newSlotName string

The new slot name.

Returns

SaveSlotInfo

The save slot info with the new name.

Exceptions

FileNotFoundException

Thrown when the source slot doesn't exist.

IOException

Thrown when the new name already exists.

SaveSlotExists(string)

Checks if a save slot exists.

public bool SaveSlotExists(string slotName)

Parameters

slotName string

The name of the save slot.

Returns

bool

True if the slot exists and is valid.

SaveToSlotAsync<TSerializer>(string, TSerializer, SaveSlotOptions?, CancellationToken)

Saves the current world state to a slot asynchronously.

public Task<SaveSlotInfo> SaveToSlotAsync<TSerializer>(string slotName, TSerializer serializer, SaveSlotOptions? options = null, CancellationToken cancellationToken = default) where TSerializer : IComponentSerializer, IBinaryComponentSerializer

Parameters

slotName string

The name of the save slot. Must be a valid filename.

serializer TSerializer

The component serializer for AOT-compatible serialization.

options SaveSlotOptions

Optional save options. Uses default if not specified.

cancellationToken CancellationToken

A cancellation token to cancel the operation.

Returns

Task<SaveSlotInfo>

The save slot info with updated metadata.

Type Parameters

TSerializer

The serializer type that implements both IComponentSerializer and IBinaryComponentSerializer.

Remarks

This async version performs file I/O without blocking the calling thread, making it suitable for use in game loops where blocking is unacceptable.

Note that snapshot creation and serialization are still synchronous CPU-bound operations. Only the file I/O is performed asynchronously.

SaveToSlot<TSerializer>(string, TSerializer, SaveSlotOptions?)

Saves the current world state to a slot.

public SaveSlotInfo SaveToSlot<TSerializer>(string slotName, TSerializer serializer, SaveSlotOptions? options = null) where TSerializer : IComponentSerializer, IBinaryComponentSerializer

Parameters

slotName string

The name of the save slot. Must be a valid filename (alphanumeric, underscores, hyphens).

serializer TSerializer

The component serializer for AOT-compatible serialization. Pass the generated ComponentSerializer from your project.

options SaveSlotOptions

Optional save options for compression, checksum, and metadata. Uses default if not specified.

Returns

SaveSlotInfo

The save slot info with updated metadata including sizes and checksum.

Type Parameters

TSerializer

The serializer type that implements both IComponentSerializer and IBinaryComponentSerializer.

Examples

// Basic save
var info = world.SaveToSlot("slot1", serializer);

// Save with options
var options = new SaveSlotOptions
{
    DisplayName = "Chapter 3 - The Forest",
    PlayTime = TimeSpan.FromHours(2.5),
    Compression = CompressionMode.Brotli
};
var info = world.SaveToSlot("slot1", serializer, options);

Exceptions

ArgumentException

Thrown when slotName is null or whitespace.

ArgumentNullException

Thrown when serializer is null.

Send<T>(in T)

Sends a message immediately to all subscribed handlers.

public void Send<T>(in T message)

Parameters

message T

The message data to send.

Type Parameters

T

The message type to send.

Examples

// Define a message type
public readonly record struct DamageMessage(Entity Target, int Amount, Entity Source);

// Subscribe to the message in a system
var subscription = world.Subscribe<DamageMessage>(msg =>
{
    ref var health = ref world.Get<Health>(msg.Target);
    health.Current -= msg.Amount;
});

// Send a message from another system
world.Send(new DamageMessage(target, 25, attacker));

Remarks

Messages are dispatched synchronously to all handlers in registration order. If no handlers are subscribed for the message type, this method returns immediately with minimal overhead (a dictionary lookup that returns false).

Use struct types for messages to minimize allocations. If a handler throws an exception, it will propagate to the caller and subsequent handlers will not be invoked.

For deferred message delivery, use QueueMessage<T>(in T) instead.

See Also

SetExtension<T>(T)

Sets or updates an extension value for this world.

public void SetExtension<T>(T extension) where T : class

Parameters

extension T

The extension instance to store.

Type Parameters

T

The extension type. Must be a reference type.

Examples

// In a plugin:
world.SetExtension(new PhysicsWorld());

// In application code:
var physics = world.GetExtension<PhysicsWorld>();
var hit = physics.Raycast(origin, direction);

Remarks

Extensions are typically set by plugins to expose custom APIs. For example, a physics plugin might expose a PhysicsWorld extension that provides raycast and collision query methods.

If an extension of type T already exists, it will be replaced.

See Also

SetParent(Entity, Entity)

Sets the parent of an entity, establishing a parent-child relationship.

public void SetParent(Entity child, Entity parent)

Parameters

child Entity

The entity to become a child.

parent Entity

The entity to become the parent. Pass KeenEyes.Entity.Null to remove the parent (make the entity a root entity).

Examples

var parent = world.Spawn().Build();
var child = world.Spawn().Build();

// Establish parent-child relationship
world.SetParent(child, parent);

// Remove parent (make child a root entity)
world.SetParent(child, Entity.Null);

Remarks

If the child already has a parent, it will be removed from the previous parent's children collection before being added to the new parent.

This operation performs cycle detection to prevent circular hierarchies. A cycle occurs when setting an ancestor as a child's parent, which would create an infinite loop in the hierarchy.

Parent lookup is O(1). Setting a parent is O(D) where D is the depth of the hierarchy due to cycle detection.

Exceptions

InvalidOperationException

Thrown when the child entity is not alive, or when setting the parent would create a circular relationship (the parent is a descendant of the child).

See Also

SetSingleton<T>(in T)

Sets or updates a singleton value for this world.

public void SetSingleton<T>(in T value) where T : struct

Parameters

value T

The singleton value to store.

Type Parameters

T

The singleton type. Must be a value type.

Examples

// Store game time as a singleton
world.SetSingleton(new GameTime { DeltaTime = 0.016f, TotalTime = 10.5f });

// Update existing singleton
world.SetSingleton(new GameTime { DeltaTime = 0.016f, TotalTime = 10.516f });

Remarks

Singletons are world-level data not tied to any entity. They are useful for storing global state like time, input, configuration, or other resources that systems need to access.

If a singleton of type T already exists, it will be replaced. Use HasSingleton<T>() to check existence before calling this method if you want to avoid overwrites.

This operation is O(1) for the dictionary-based storage implementation.

See Also

Set<T>(Entity, in T)

Sets (replaces) a component value on an entity that already has this component.

public void Set<T>(Entity entity, in T value) where T : struct, IComponent

Parameters

entity Entity

The entity to update the component on.

value T

The new component value.

Type Parameters

T

The component type to update.

Examples

world.Set(entity, new Position { X = 100, Y = 200 });

Exceptions

InvalidOperationException

Thrown when the entity is not alive, the component type is not registered, or the entity does not have the specified component. Use With<T>(T) to add new components during entity creation.

Spawn()

Begins building a new entity.

public EntityBuilder Spawn()

Returns

EntityBuilder

A fluent builder for adding components.

Spawn(string?)

Begins building a new entity with an optional name.

public EntityBuilder Spawn(string? name)

Parameters

name string

The optional name for the entity. If provided, must be unique within this world. Can be null for unnamed entities.

Returns

EntityBuilder

A fluent builder for adding components.

Examples

var player = world.Spawn("Player")
    .With(new Position { X = 0, Y = 0 })
    .With(new Health { Current = 100, Max = 100 })
    .Build();

// Later, retrieve by name
var foundPlayer = world.GetEntityByName("Player");

Remarks

Named entities can be retrieved later using GetEntityByName(string). This is useful for debugging, editor tooling, and scenarios where entities need human-readable identifiers.

Names must be unique within a world. Attempting to create an entity with a name that is already in use will throw an ArgumentException.

Exceptions

ArgumentException

Thrown when a non-null name is already assigned to another entity in this world.

See Also

SpawnFromPrefab(string)

Spawns an entity from a registered prefab.

public IEntityBuilder SpawnFromPrefab(string name)

Parameters

name string

The name of the prefab to spawn from.

Returns

IEntityBuilder

An entity builder pre-configured with the prefab's components. Call KeenEyes.IEntityBuilder.Build() to create the entity.

Examples

// Spawn with default prefab values
var enemy1 = world.SpawnFromPrefab("Enemy").Build();

// Spawn with overridden position
var enemy2 = world.SpawnFromPrefab("Enemy")
    .With(new Position { X = 100, Y = 50 })
    .Build();

Remarks

The returned builder can be used to add additional components or apply overrides before creating the entity. This allows customizing individual instances while still using the prefab as a base template.

If the prefab has a base prefab (via Extends(string)), the inheritance chain is resolved and all inherited components are included.

Exceptions

ArgumentNullException

Thrown when name is null.

InvalidOperationException

Thrown when no prefab with the given name is registered, or when the prefab has a circular inheritance chain.

See Also

SpawnFromPrefab(string, string?)

Spawns a named entity from a registered prefab.

public IEntityBuilder SpawnFromPrefab(string prefabName, string? entityName)

Parameters

prefabName string

The name of the prefab to spawn from.

entityName string

The name for the spawned entity, or null for an unnamed entity. Must be unique within this world if provided.

Returns

IEntityBuilder

An entity builder pre-configured with the prefab's components. Call KeenEyes.IEntityBuilder.Build() to create the entity.

Examples

// Spawn a named entity from a prefab
var player = world.SpawnFromPrefab("Player", "MainPlayer").Build();

// Later, retrieve by name
var foundPlayer = world.GetEntityByName("MainPlayer");

Remarks

Named entities can be retrieved later using GetEntityByName(string). This is useful for scenarios where entities need human-readable identifiers, such as debugging or editor tooling.

Exceptions

ArgumentNullException

Thrown when prefabName is null.

InvalidOperationException

Thrown when no prefab with the given name is registered, or when the prefab has a circular inheritance chain.

ArgumentException

Thrown when entityName is already assigned to another entity.

See Also

Subscribe<T>(Action<T>)

Subscribes a handler to messages of the specified type.

public EventSubscription Subscribe<T>(Action<T> handler)

Parameters

handler Action<T>

The handler to invoke when messages of type T are sent.

Returns

EventSubscription

An KeenEyes.EventSubscription that can be disposed to unsubscribe the handler.

Type Parameters

T

The message type to subscribe to.

Examples

// Subscribe to damage messages
var subscription = world.Subscribe<DamageMessage>(msg =>
{
    Console.WriteLine($"Entity {msg.Target} took {msg.Amount} damage");
});

// Later, unsubscribe
subscription.Dispose();

Remarks

Handlers are invoked synchronously in registration order when messages are sent. The same handler instance can be registered multiple times, in which case it will be invoked multiple times per message. Each registration returns a separate subscription.

To unsubscribe, call KeenEyes.EventSubscription.Dispose() on the returned subscription. Subscriptions are idempotent: disposing the same subscription multiple times has no additional effect.

Exceptions

ArgumentNullException

Thrown when handler is null.

See Also

TryGetExtension<T>(out T)

Tries to get an extension by type.

public bool TryGetExtension<T>(out T extension) where T : class

Parameters

extension T

When this method returns, contains the extension if found; otherwise, null.

Returns

bool

True if the extension was found; false otherwise.

Type Parameters

T

The extension type to retrieve.

Examples

if (world.TryGetExtension<PhysicsWorld>(out var physics))
{
    var hit = physics.Raycast(origin, direction);
}

TryGetSingleton<T>(out T)

Attempts to get a singleton value.

public bool TryGetSingleton<T>(out T value) where T : struct

Parameters

value T

When this method returns true, contains the singleton value. When this method returns false, contains the default value of T.

Returns

bool

true if the singleton exists; false otherwise.

Type Parameters

T

The singleton type to retrieve.

Examples

if (world.TryGetSingleton<GameTime>(out var time))
{
    Console.WriteLine($"Delta: {time.DeltaTime}");
}
else
{
    Console.WriteLine("GameTime singleton not set");
}

Remarks

This method provides a safe way to retrieve singletons without throwing exceptions. Unlike GetSingleton<T>(), this method returns a copy of the value rather than a reference, so modifications will not affect the stored singleton.

Use GetSingleton<T>() when you need zero-copy access or want to modify the singleton in place.

This operation is O(1) for the dictionary-based storage implementation.

See Also

UninstallPlugin(string)

Uninstalls a plugin by name from this world.

public bool UninstallPlugin(string name)

Parameters

name string

The name of the plugin to uninstall.

Returns

bool

True if the plugin was found and uninstalled; false otherwise.

UninstallPlugin<T>()

Uninstalls a plugin from this world.

public bool UninstallPlugin<T>() where T : IWorldPlugin

Returns

bool

True if the plugin was found and uninstalled; false otherwise.

Type Parameters

T

The plugin type to uninstall.

Examples

world.UninstallPlugin<PhysicsPlugin>();

Remarks

The plugin's KeenEyes.IWorldPlugin.Uninstall(KeenEyes.IPluginContext) method is called during uninstallation. All systems registered by the plugin are automatically removed and disposed.

UnregisterPrefab(string)

Unregisters a prefab by name.

public bool UnregisterPrefab(string name)

Parameters

name string

The name of the prefab to remove.

Returns

bool

true if the prefab was removed; false if it wasn't registered.

Remarks

Unregistering a prefab does not affect entities that were already spawned from it. Those entities continue to exist with their components intact.

Exceptions

ArgumentNullException

Thrown when name is null.

UnregisterValidator<T>()

Removes a previously registered custom validator for a component type.

public bool UnregisterValidator<T>() where T : struct, IComponent

Returns

bool

true if a validator was removed; false if no validator was registered.

Type Parameters

T

The component type.

Update(float)

Updates all enabled systems with the given delta time.

public void Update(float deltaTime)

Parameters

deltaTime float

The time elapsed since the last update.

Remarks

Systems are executed in order of their phase (earliest first), then by their order value within each phase (lowest first). Disabled systems are skipped.

For systems derived from KeenEyes.SystemBase, the following lifecycle methods are called in order: OnBeforeUpdate, Update, OnAfterUpdate.

ValidateSaveSlot(string)

Validates a save slot's integrity.

public SaveSlotInfo? ValidateSaveSlot(string slotName)

Parameters

slotName string

The name of the save slot to validate.

Returns

SaveSlotInfo

The validation result with any errors. Returns null if the file doesn't exist or is completely invalid. Check IsValid and ValidationError for details.

ValidateSaveSlotAsync(string, CancellationToken)

Validates a save slot's integrity asynchronously.

public Task<SaveSlotInfo?> ValidateSaveSlotAsync(string slotName, CancellationToken cancellationToken = default)

Parameters

slotName string

The name of the save slot to validate.

cancellationToken CancellationToken

A cancellation token to cancel the operation.

Returns

Task<SaveSlotInfo>

The validation result with any errors. Returns null if the file doesn't exist.