ecspresso
Version:
A minimal Entity-Component-System library for typescript and javascript.
121 lines (120 loc) • 4.92 kB
TypeScript
import type ECSpresso from './ecspresso';
import type { RemoveEntityOptions } from './types';
import type { WorldConfig, EmptyConfig } from './type-utils';
/**
* CommandBuffer queues structural changes to be executed later.
* This prevents ordering issues when modifying entities during system execution.
*
* Commands are executed in FIFO order when playback() is called.
*
* @example
* ```typescript
* // In a system
* ecs.commands.removeEntity(entityId);
* ecs.commands.spawn({ position: { x: 0, y: 0 } });
*
* // Later (automatically at end of update())
* ecs.commands.playback(ecs);
* ```
*/
export default class CommandBuffer<Cfg extends WorldConfig = EmptyConfig> {
private readonly parent?;
private commands;
/**
* @param parent Owning ECS instance, used to read the active scope hint at
* queue time so screen-gated spawns get auto-scoped on playback. Optional
* so the buffer can be constructed standalone in tests.
*/
constructor(parent?: ECSpresso<Cfg> | undefined);
/**
* Queue an entity removal command
* @param entityId The entity ID to remove
* @param options Optional removal options (cascade, etc.)
*/
removeEntity(entityId: number, options?: RemoveEntityOptions): void;
/**
* Queue a component addition command
* @param entityId The entity ID
* @param componentName The name of the component to add
* @param componentValue The component data
*/
addComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K, componentValue: Cfg['components'][K]): void;
/**
* Queue a component removal command
* @param entityId The entity ID
* @param componentName The name of the component to remove
*/
removeComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K): void;
/**
* Queue an entity spawn command
* @param components The initial components for the new entity
* @returns void (entity ID not available until playback)
*/
spawn<T extends {
[K in keyof Cfg['components']]?: Cfg['components'][K];
}>(components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>, options?: {
scope?: (keyof Cfg['screens'] & string) | null;
}): void;
/**
* Queue a child entity spawn command
* @param parentId The parent entity ID
* @param components The initial components for the new child entity
*/
spawnChild<T extends {
[K in keyof Cfg['components']]?: Cfg['components'][K];
}>(parentId: number, components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>, options?: {
scope?: (keyof Cfg['screens'] & string) | null;
}): void;
/**
* Snapshot the parent ECS's active scope hint at queue time when the
* caller didn't pass an explicit scope. Without this, playback (after the
* tick ends) would see a null hint and the gated system's screen intent
* would be lost.
*/
private _resolveScope;
/**
* Queue multiple component additions
* @param entityId The entity ID
* @param components Object with component names as keys and component data as values
*/
addComponents<T extends {
[K in keyof Cfg['components']]?: Cfg['components'][K];
}>(entityId: number, components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>): void;
/**
* Queue a parent assignment command
* @param childId The child entity ID
* @param parentId The parent entity ID
*/
setParent(childId: number, parentId: number): void;
/**
* Queue a component mutation command.
* The mutator runs during playback, receiving the component for in-place mutation.
* Automatically marks the component as changed.
* @param entityId The entity ID
* @param componentName The component to mutate
* @param mutator A function that receives the component value for in-place mutation
*/
mutateComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K, mutator: (value: Cfg['components'][K]) => void): void;
/** Queue a markChanged command for playback. */
markChanged<K extends keyof Cfg['components']>(entityId: number, componentName: K): void;
/**
* Queue a parent removal command
* @param childId The child entity ID
*/
removeParent(childId: number): void;
/**
* Execute all queued commands in FIFO order.
* Errors from individual commands are caught and logged, but do not stop playback.
* @param ecs The ECSpresso instance to execute commands on
*/
playback(ecs: ECSpresso<Cfg>): void;
/**
* Clear all queued commands without executing them
*/
clear(): void;
/**
* Get the number of queued commands
* @returns The number of commands waiting to be executed
*/
get length(): number;
}