import { TransformNode } from '@babylonjs/core'; import { GameEntity, RequestResult } from "../classes/entity.d.ts"; import { GameEventBus } from "../classes/eventBus.d.ts"; import { GameEngine } from "../classes/gameEngine.d.ts"; import { GameEntityDefinition } from "../interfaces/entity.d.ts"; import { Disposable } from "../interfaces/lifecycle.d.ts"; import { BindingManager } from "../managers/binding.d.ts"; import { LoggingUtility } from "../utils/logger.d.ts"; /** * Options for creating an entity instance. */ export interface CreateEntityOptions { /** Initial state to merge with defaultState. */ initialState?: Partial; /** Override name from entity definition. */ name?: string; /** Additional tags to add (merged with definition tags). */ tags?: string[]; /** Scene node to attach the entity to. */ node?: TransformNode; } export declare class GameEntityManager implements Disposable { /** The event bus for the entity manager. */ private eventBus; /** A map of entities managed by the entity manager. */ private entities; /** A map of entity definitions registered with the entity manager. */ private entityDefinitions; /** Late-bound GameEngine reference */ private _gameEngine; /** Reference to the binding manager for registering actions */ private bindingManager; /** Logger instance */ private _log; /** Index: name -> entity (names are not unique, first match returned by getByName) */ private _entitiesByName; /** Index: type -> entities */ private _entitiesByType; /** Index: tag -> entities */ private _entitiesByTag; /** Index: node -> entity (one entity per node) */ private _entitiesByNode; /** Object pool storage: type -> pooled entities */ private _pools; /** * Creates an instance of EntityManager. * @param eventBus * @param logger * @param bindingManager */ constructor(eventBus: GameEventBus, logger: LoggingUtility | undefined, bindingManager: BindingManager); /** * Late-bind the GameEngine after construction. * Called by createGameEngine() after the GameEngine instance is created. */ $setGameEngine(gameEngine: GameEngine): void; private get _engine(); /** * Gets or creates a Set in a Map, returning the Set. */ private _getOrCreateSet; /** * Adds an entity to all relevant indices. */ private _indexEntity; /** * Removes an entity from all indices. */ private _unindexEntity; /** * Resolves an entity definition that extends a base definition by merging according to inheritance rules. * The base definition must already be registered. */ private _resolveInheritance; /** * Checks if two actions are compatible (same type and non-conflicting options). * @param existingAction - The action already registered * @param newAction - The action being registered */ private _areActionsCompatible; /** * Registers actions defined in the entity definition with the binding manager. * Skips actions already registered with compatible options; warns on conflicts. * @param entityDef */ private _registerEntityActions; $frameUpdate(dt: number): void; /** * Registers a new entity definition. * Also registers any actions declared in the definition with the binding manager. * @param entityDef */ registerEntityDefinition(entityDef: GameEntityDefinition): void; /** * Retrieve an entity definition by type. * @param type */ getDefinition(type: string): GameEntityDefinition | undefined; /** * Creates a new entity of the given type. * Runs onBeforeCreate/onCreate lifecycle hooks, merges state, applies tags, and indexes the entity. * @param type - Must match a previously registered entity definition * @param options */ createEntity(type: string, options?: CreateEntityOptions): Promise>; /** * Destroys the entity with the given ID. * Runs onBeforeDestroy/onDestroy lifecycle hooks, unindexes, and removes the entity. * @param entityID */ destroyEntity(entityID: string): Promise; /** * Gets the entity with the given ID. * @param entityID */ getEntity(entityID: string): GameEntity | null; /** * Adds an existing entity to the entity manager and indexes it. * @param entity */ addEntity(entity: GameEntity): void; /** * Removes the entity with the given ID, without destroying it. * @param entityID */ removeEntity(entityID: string): void; /** * Adds a child entity to a parent entity. * @param parentId - ID of the parent entity * @param childId - ID of the child entity * @returns False if either entity is not found */ addChild(parentId: string, childId: string): boolean; /** * Removes a child entity from a parent entity. * @param parentId - ID of the parent entity * @param childId - ID of the child entity * @returns False if either entity is not found */ removeChild(parentId: string, childId: string): boolean; /** * Gets the first entity with the given name. * Names are not unique; use getEntitiesByName() to retrieve all matches. * @param name */ getByName(name: string): GameEntity | undefined; /** * Gets all entities with the given name. * @param name */ getEntitiesByName(name: string): GameEntity[]; /** * Gets all entities of the given type. * @param type */ getByType(type: string): GameEntity[]; /** * Gets all entities with the given tag. * @param tag */ getByTag(tag: string): GameEntity[]; /** * Gets all entities matching multiple tags. * @param tags * @param mode - 'all' requires every tag (intersection), 'any' requires at least one (union) */ getByTags(tags: string[], mode?: 'all' | 'any'): GameEntity[]; /** * Returns an iterator over all entities. * More memory-efficient than returning an array for large entity counts. */ getAllEntities(): IterableIterator; /** * Gets the total number of entities. */ get entityCount(): number; /** * Sends a fire-and-forget event directly to a specific entity's behaviors, bypassing the event bus. * Resolves the target by entity ID first (O(1)), then falls back to name lookup (O(1)). * * @param target - Entity ID or name * @param type - Event type string * @param payload - Optional event payload */ send(target: string, type: string, payload?: unknown, senderID?: string): Promise; /** * Sends a request to a specific entity's behaviors and returns the first response. * Resolves the target by entity ID first (O(1)), then falls back to name lookup (O(1)). * * @param target - Entity ID or name * @param type - Request type string * @param payload - Optional request payload * @param senderID - Optional sender entity ID (stamped on the event) */ request(target: string, type: string, payload?: unknown, senderID?: string): Promise>; /** * Adds a tag to an entity and updates the tag index. * @param entity - Entity instance or entity ID * @param tag * @returns False if already present or entity not found */ addTag(entity: GameEntity | string, tag: string): boolean; /** * Removes a tag from an entity and updates the tag index. * @param entity - Entity instance or entity ID * @param tag * @returns False if not present or entity not found */ removeTag(entity: GameEntity | string, tag: string): boolean; /** * Gets an entity by its attached scene node. * @param node */ getByNode(node: TransformNode): GameEntity | undefined; /** * Attaches an entity to a scene node. * The entity will reference this node and can be looked up via getByNode(). * * @param entity - Entity instance or entity ID * @param node * @returns False if entity not found or node already has an entity */ attachToNode(entity: GameEntity | string, node: TransformNode): boolean; /** * Detaches an entity from its scene node. * * @param entity - Entity instance or entity ID * @returns False if entity not found or had no node */ detachFromNode(entity: GameEntity | string): boolean; /** * Pre-creates entities and pools them for fast recycling. * @param type - Entity type to prewarm * @param count - Number of entities to create and pool */ prewarm(type: string, count: number): Promise; /** * Drains the pool for a given type, actually destroying all pooled entities. * @param type - Entity type whose pool to drain */ drainPool(type: string): Promise; /** * Tears down all entities and releases resources. * Destroys entities individually (running lifecycle hooks), then clears definitions and indices. */ $teardown(): Promise; }