Table of Contents

Interface ICommandBuffer

Namespace
KeenEyes
Assembly
KeenEyes.Abstractions.dll

Queues entity operations for deferred execution, enabling safe modification during system iteration.

public interface ICommandBuffer

Examples

// During system iteration
var buffer = new CommandBuffer();
foreach (var entity in world.Query<Health>())
{
    ref var health = ref world.Get<Health>(entity);
    if (health.Current <= 0)
    {
        buffer.Despawn(entity);  // Queue for later, don't invalidate iterator
    }
}

// After iteration
buffer.Flush(world);  // Execute all queued commands

Remarks

CommandBuffer is the solution to iterator invalidation when modifying entities during queries. Instead of directly spawning, despawning, or modifying components during iteration, operations are queued and executed atomically after iteration completes.

Thread Safety: CommandBuffer is not thread-safe. Each system should use its own buffer, or access should be synchronized externally.

Performance: The buffer maintains O(N) performance where N is the number of commands. Commands are stored in a list and executed in order during Flush(IWorld).

Execution Order: Commands are executed in the order they were queued. Spawn commands create placeholder-to-real entity mappings, allowing subsequent commands to reference newly created entities.

Properties

Count

Gets the number of commands currently queued in the buffer.

int Count { get; }

Property Value

int

Methods

AddComponent<T>(Entity, T)

Queues a command to add a component to an existing entity.

void AddComponent<T>(Entity entity, T component) where T : struct, IComponent

Parameters

entity Entity

The entity to add the component to.

component T

The component value.

Type Parameters

T

The component type to add.

Examples

// Add a power-up component to entities that collected a power-up
buffer.AddComponent(entity, new PowerUp { Type = PowerUpType.Speed, Duration = 10f });

Remarks

The component is not added until Flush(IWorld) is called. If the entity is not alive or already has the component at flush time, the behavior matches Add<T>(Entity, in T).

AddComponent<T>(int, T)

Queues a command to add a component to an entity referenced by placeholder ID.

void AddComponent<T>(int placeholderId, T component) where T : struct, IComponent

Parameters

placeholderId int

The placeholder ID from a previous Spawn call.

component T

The component value.

Type Parameters

T

The component type to add.

Clear()

Clears all queued commands without executing them.

void Clear()

Remarks

Use this to abandon queued commands. The buffer can be reused after clearing.

Despawn(Entity)

Queues a command to despawn an existing entity.

void Despawn(Entity entity)

Parameters

entity Entity

The entity to despawn.

Examples

foreach (var entity in world.Query<Health>())
{
    ref var health = ref world.Get<Health>(entity);
    if (health.Current <= 0)
    {
        buffer.Despawn(entity);
    }
}

Remarks

The entity is not destroyed until Flush(IWorld) is called. If the entity is not alive at flush time, the command is silently ignored.

Despawn(int)

Queues a command to despawn an entity referenced by placeholder ID.

void Despawn(int placeholderId)

Parameters

placeholderId int

The placeholder ID from a previous Spawn call.

Remarks

This allows despawning entities that were spawned in the same command buffer before Flush(IWorld) is called.

Flush(IWorld)

Executes all queued commands on the specified world and clears the buffer.

Dictionary<int, Entity> Flush(IWorld world)

Parameters

world IWorld

The world to execute commands on.

Returns

Dictionary<int, Entity>

A dictionary mapping placeholder entity IDs to the real entities created. This allows callers to track which entities were spawned.

Examples

var cmd1 = buffer.Spawn().With(new Position { X = 0, Y = 0 });
var cmd2 = buffer.Spawn().With(new Position { X = 10, Y = 10 });

var entityMap = buffer.Flush(world);

var entity1 = entityMap[cmd1.PlaceholderId];  // Get the real entity
var entity2 = entityMap[cmd2.PlaceholderId];

Remarks

Commands are executed in the order they were queued. Spawn commands are processed first in sequence, creating the placeholder-to-entity mapping that subsequent commands can use.

After execution, the buffer is cleared and ready for reuse.

Exception Handling: If a command throws an exception, subsequent commands are not executed. The buffer is still cleared to prevent duplicate execution.

RemoveComponent<T>(Entity)

Queues a command to remove a component from an existing entity.

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

Parameters

entity Entity

The entity to remove the component from.

Type Parameters

T

The component type to remove.

Examples

// Remove frozen status from entities that thaw
buffer.RemoveComponent<FrozenTag>(entity);

Remarks

The component is not removed until Flush(IWorld) is called. If the entity is not alive or does not have the component at flush time, the command is silently ignored (matches Remove<T>(Entity) behavior).

RemoveComponent<T>(int)

Queues a command to remove a component from an entity referenced by placeholder ID.

void RemoveComponent<T>(int placeholderId) where T : struct, IComponent

Parameters

placeholderId int

The placeholder ID from a previous Spawn call.

Type Parameters

T

The component type to remove.

SetComponent<T>(Entity, T)

Queues a command to set (replace) a component value on an existing entity.

void SetComponent<T>(Entity entity, T component) where T : struct, IComponent

Parameters

entity Entity

The entity to set the component on.

component T

The new component value.

Type Parameters

T

The component type to set.

Examples

// Update position after calculating new location
buffer.SetComponent(entity, new Position { X = newX, Y = newY });

Remarks

The component is not updated until Flush(IWorld) is called. If the entity is not alive or does not have the component at flush time, the behavior matches Set<T>(Entity, in T). Use AddComponent<T>(Entity, T) to add a new component.

SetComponent<T>(int, T)

Queues a command to set (replace) a component value on an entity referenced by placeholder ID.

void SetComponent<T>(int placeholderId, T component) where T : struct, IComponent

Parameters

placeholderId int

The placeholder ID from a previous Spawn call.

component T

The new component value.

Type Parameters

T

The component type to set.

Spawn()

Queues a spawn command and returns a fluent builder for adding components.

EntityCommands Spawn()

Returns

EntityCommands

An EntityCommands builder for configuring the new entity.

Examples

var entityCmd = buffer.Spawn()
    .With(new Position { X = 0, Y = 0 })
    .With(new Velocity { X = 1, Y = 0 });

// Use placeholder to add more components later
buffer.AddComponent(entityCmd.PlaceholderId, new Health { Current = 100, Max = 100 });

Remarks

The entity is not created until Flush(IWorld) is called. Use the returned builder to add components to the entity.

Each call to Spawn generates a unique placeholder ID (negative value) that can be used to reference the entity in subsequent commands.

Spawn(string?)

Queues a spawn command with an optional name and returns a fluent builder for adding components.

EntityCommands Spawn(string? name)

Parameters

name string

The optional name for the entity. If provided, must be unique within the world at flush time.

Returns

EntityCommands

An EntityCommands builder for configuring the new entity.

Examples

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

buffer.Flush(world);

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

Remarks

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

The entity is not created until Flush(IWorld) is called. If the name is already in use at flush time, an exception will be thrown.