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
-
IWorldISystemHookCapabilityIPersistenceCapabilityIHierarchyCapabilityIValidationCapabilityITagCapabilityIPrefabCapabilityIStatisticsCapabilityIInspectionCapabilityISnapshotCapability
- 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
seedint?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
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
Components
The component registry for this world. Component IDs are unique per-world, not global.
public ComponentRegistry Components { get; }
Property Value
EntityCount
Gets the total number of entities in the world.
public int EntityCount { get; }
Property Value
Events
Gets the event bus for publishing and subscribing to custom events.
public EventBus Events { get; }
Property Value
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
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
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
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
parentEntityThe parent entity.
childEntityThe 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
systemISystemThe system instance to add.
phaseSystemPhaseThe execution phase for this system. Defaults to KeenEyes.SystemPhase.Update.
orderintThe 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
systemISystemThe system instance to add.
phaseSystemPhaseThe execution phase for this system.
orderintThe execution order within the phase. Lower values execute first.
runsBeforeType[]Types of systems that this system must run before.
runsAfterType[]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
beforeHookSystemHookOptional callback to invoke before each system execution.
afterHookSystemHookOptional callback to invoke after each system execution.
phaseSystemPhase?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
phaseSystemPhaseThe execution phase for this system. Defaults to KeenEyes.SystemPhase.Update.
orderintThe execution order within the phase. Lower values execute first. Defaults to 0.
Returns
- World
This world for method chaining.
Type Parameters
TThe 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
phaseSystemPhaseThe execution phase for this system.
orderintThe execution order within the phase. Lower values execute first.
runsBeforeType[]Types of systems that this system must run before.
runsAfterType[]Types of systems that this system must run after.
Returns
- World
This world for method chaining.
Type Parameters
TThe 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
entityEntityThe entity to add the tag to.
tagstringThe tag to add. Cannot be null, empty, or whitespace.
Returns
- bool
trueif the tag was added;falseif 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
tagis null.- ArgumentException
Thrown when
tagis 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
entityEntityThe entity to add the component to.
componentTThe component value to add.
Type Parameters
TThe 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
TThe 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
TThe 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
sourceSlotNamestringThe source slot name.
destinationSlotNamestringThe destination slot name.
overwriteboolWhether 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
sourceSlotNamestringThe source slot name.
destinationSlotNamestringThe destination slot name.
overwriteboolWhether to overwrite if destination exists.
cancellationTokenCancellationTokenA 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
slotNamestringThe 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
slotNamestringThe name of the save slot to delete.
cancellationTokenCancellationTokenA cancellation token to cancel the operation.
Returns
Despawn(Entity)
Destroys an entity and all its components.
public bool Despawn(Entity entity)
Parameters
entityEntityThe 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
entityEntityThe 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
TThe 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
TThe 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
TThe 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
TThe 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
fixedDeltaTimefloatThe 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
entityEntityThe 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
entityEntityThe 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
entityEntityThe 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
entityEntityThe 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
TThe 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
TThe 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
namestringThe 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
TThe extension type to retrieve.
Examples
var physics = world.GetExtension<PhysicsWorld>();
var hit = physics.Raycast(origin, direction);
Exceptions
- InvalidOperationException
Thrown when no extension of type
Texists 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
TThe 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
entityEntityThe entity to get the name for.
Returns
- string
The name assigned to the entity, or
nullif 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
entityEntityThe 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
namestringThe 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
TThe 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
TThe 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
entityEntityThe 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
slotNamestringThe 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
slotNamestringThe name of the save slot.
cancellationTokenCancellationTokenA 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
slotNamestringThe 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
TThe 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
Texists 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
TThe 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
entityEntityThe 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
entityEntityThe entity to get the component from.
Returns
- T
A reference to the component data for zero-copy access.
Type Parameters
TThe 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
entityEntityThe entity to check.
componentTypeTypeThe component type to check for.
Returns
- bool
trueif the entity has the component;falseotherwise.
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
TThe 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
trueif at least one handler is subscribed; otherwise,false.
Type Parameters
TThe 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
namestringThe 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
TThe plugin type to check for.
HasPrefab(string)
Checks if a prefab with the given name is registered.
public bool HasPrefab(string name)
Parameters
namestringThe name to check.
Returns
- bool
trueif a prefab with the name exists; otherwise,false.
Examples
if (world.HasPrefab("Enemy"))
{
var enemy = world.SpawnFromPrefab("Enemy").Build();
}
Exceptions
- ArgumentNullException
Thrown when
nameis null.
HasSingleton<T>()
Checks if a singleton of the specified type exists in this world.
public bool HasSingleton<T>() where T : struct
Returns
- bool
trueif a singleton of typeTexists;falseotherwise.
Type Parameters
TThe 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
entityEntityThe entity to check.
tagstringThe tag to check for. Cannot be null, empty, or whitespace.
Returns
- bool
trueif the entity is alive and has the specified tag;falseif 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
tagis null.- ArgumentException
Thrown when
tagis 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
entityEntityThe entity to check.
Returns
- bool
trueif the entity is alive and has the specified component;falseif the entity is not alive, the component type is not registered, or the entity does not have the component.
Type Parameters
TThe 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
pluginIWorldPluginThe 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
TThe 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
entityEntity
Returns
IsAutoTrackingEnabled<T>()
Checks if automatic dirty tracking is enabled for a component type.
public bool IsAutoTrackingEnabled<T>() where T : struct, IComponent
Returns
- bool
trueif auto-tracking is enabled;falseotherwise.
Type Parameters
TThe 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
entityEntityThe entity to check.
Returns
- bool
trueif the entity is marked dirty for the component type;falseif not dirty or the entity is not alive.
Type Parameters
TThe 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
cancellationTokenCancellationTokenA 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
slotNamestringThe name of the save slot to load.
serializerTSerializerThe component serializer for AOT-compatible deserialization.
validateChecksumboolWhether to validate the checksum if present. Defaults to true.
cancellationTokenCancellationTokenA 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
TSerializerThe 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
slotNamestringThe name of the save slot to load.
serializerTSerializerThe component serializer for AOT-compatible deserialization. Pass the generated ComponentSerializer from your project.
validateChecksumboolWhether 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
TSerializerThe 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
entityEntityThe entity to mark as dirty.
Type Parameters
TThe 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
probabilityfloatThe 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
maxValueintThe 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
minValueintThe inclusive lower bound of the random number returned.
maxValueintThe 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
handlerAction<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
TThe 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
handlerAction<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
TThe 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
handlerAction<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
TThe 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
handlerAction<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
handlerAction<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
initialCapacityintInitial capacity for entity storage. Defaults to 16.
Type Parameters
TBundleThe 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
initialCapacityintInitial capacity for entity storage. Defaults to 16.
Type Parameters
T1The 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
initialCapacityintInitial capacity for entity storage. Defaults to 16.
Type Parameters
T1The first component type.
T2The 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
initialCapacityintInitial capacity for entity storage. Defaults to 16.
Type Parameters
T1The first component type.
T2The second component type.
T3The 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
initialCapacityintInitial capacity for entity storage. Defaults to 16.
Type Parameters
T1The first component type.
T2The second component type.
T3The third component type.
T4The 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
TThe 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
tagstringThe 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
tagis null.- ArgumentException
Thrown when
tagis 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
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
Type Parameters
T1T2
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
Type Parameters
T1T2T3
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
Type Parameters
T1T2T3T4
QueueMessage<T>(in T)
Queues a message for deferred delivery.
public void QueueMessage<T>(in T message)
Parameters
messageTThe message data to queue.
Type Parameters
TThe 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
namestringThe unique name for the prefab.
prefabEntityPrefabThe 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
nameorprefabis 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
validatorComponentValidator<T>A delegate that receives the world, entity, and component data, and returns
trueif validation passes.
Type Parameters
TThe 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
validatoris null.
RemoveChild(Entity, Entity)
Removes a specific child from a parent entity.
public bool RemoveChild(Entity parent, Entity child)
Parameters
parentEntityThe parent entity.
childEntityThe child entity to remove from the parent.
Returns
- bool
trueif the child was removed from the parent;falseif 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
TThe extension type to remove.
RemoveSingleton<T>()
Removes a singleton from this world.
public bool RemoveSingleton<T>() where T : struct
Returns
- bool
trueif the singleton was removed;falseif no singleton of typeTexisted.
Type Parameters
TThe 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
entityEntityThe entity to remove the tag from.
tagstringThe tag to remove. Cannot be null, empty, or whitespace.
Returns
- bool
trueif the tag was removed;falseif 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
tagis null.- ArgumentException
Thrown when
tagis 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
entityEntityThe entity to remove the component from.
Returns
- bool
trueif the component was removed;falseif the entity is not alive, the component type is not registered, or the entity does not have the component.
Type Parameters
TThe 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
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
slotNamestringThe 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
slotNamestringThe name of the save slot. Must be a valid filename.
serializerTSerializerThe component serializer for AOT-compatible serialization.
optionsSaveSlotOptionsOptional save options. Uses default if not specified.
cancellationTokenCancellationTokenA cancellation token to cancel the operation.
Returns
- Task<SaveSlotInfo>
The save slot info with updated metadata.
Type Parameters
TSerializerThe 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
slotNamestringThe name of the save slot. Must be a valid filename (alphanumeric, underscores, hyphens).
serializerTSerializerThe component serializer for AOT-compatible serialization. Pass the generated ComponentSerializer from your project.
optionsSaveSlotOptionsOptional 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
TSerializerThe 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
messageTThe message data to send.
Type Parameters
TThe 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
extensionTThe extension instance to store.
Type Parameters
TThe 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
childEntityThe entity to become a child.
parentEntityThe 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
valueTThe singleton value to store.
Type Parameters
TThe 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
entityEntityThe entity to update the component on.
valueTThe new component value.
Type Parameters
TThe 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
namestringThe optional name for the entity. If provided, must be unique within this world. Can be
nullfor 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
namestringThe 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
nameis 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
prefabNamestringThe name of the prefab to spawn from.
entityNamestringThe name for the spawned entity, or
nullfor 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
prefabNameis null.- InvalidOperationException
Thrown when no prefab with the given name is registered, or when the prefab has a circular inheritance chain.
- ArgumentException
Thrown when
entityNameis 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
handlerAction<T>The handler to invoke when messages of type
Tare sent.
Returns
- EventSubscription
An KeenEyes.EventSubscription that can be disposed to unsubscribe the handler.
Type Parameters
TThe 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
handleris 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
extensionTWhen this method returns, contains the extension if found; otherwise, null.
Returns
- bool
True if the extension was found; false otherwise.
Type Parameters
TThe 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
valueTWhen this method returns
true, contains the singleton value. When this method returnsfalse, contains the default value ofT.
Returns
- bool
trueif the singleton exists;falseotherwise.
Type Parameters
TThe 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
namestringThe 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
TThe 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
namestringThe name of the prefab to remove.
Returns
- bool
trueif the prefab was removed;falseif 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
nameis null.
UnregisterValidator<T>()
Removes a previously registered custom validator for a component type.
public bool UnregisterValidator<T>() where T : struct, IComponent
Returns
- bool
trueif a validator was removed;falseif no validator was registered.
Type Parameters
TThe component type.
Update(float)
Updates all enabled systems with the given delta time.
public void Update(float deltaTime)
Parameters
deltaTimefloatThe 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
slotNamestringThe 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
slotNamestringThe name of the save slot to validate.
cancellationTokenCancellationTokenA cancellation token to cancel the operation.
Returns
- Task<SaveSlotInfo>
The validation result with any errors. Returns null if the file doesn't exist.