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
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
entityEntityThe entity to add the component to.
componentTThe component value.
Type Parameters
TThe 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
placeholderIdintThe placeholder ID from a previous Spawn call.
componentTThe component value.
Type Parameters
TThe 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
entityEntityThe 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
placeholderIdintThe 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
worldIWorldThe 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
entityEntityThe entity to remove the component from.
Type Parameters
TThe 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
placeholderIdintThe placeholder ID from a previous Spawn call.
Type Parameters
TThe 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
entityEntityThe entity to set the component on.
componentTThe new component value.
Type Parameters
TThe 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
placeholderIdintThe placeholder ID from a previous Spawn call.
componentTThe new component value.
Type Parameters
TThe 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
namestringThe 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.