UNPKG

ecspresso

Version:

A minimal Entity-Component-System library for typescript and javascript.

121 lines (120 loc) 4.92 kB
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; }