@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
228 lines • 8.09 kB
TypeScript
export type EntityManagerState = number;
export namespace EntityManagerState {
let Initial: number;
let Starting: number;
let Running: number;
let Failed: number;
let Stopping: number;
let Stopped: number;
}
/**
* Brings together {@link System}s and an {@link EntityComponentDataset}
* Main entry point into the simulation process.
*
* @example
* const em = new EntityManager()
*
* em.addSystem(new MySystem())
* em.addSystem(new MyOtherSystem())
*
* em.attachDataset(new EntityComponentDataset())
*
* em.startup();
*
* // ..
*
* em.simulate(0.016); // advance simulation forward by 16ms
*
* // ..
*
* em.shutdown();
*
* // ..
*
* em.detachDataset();
*
* @author Alex Goldring
* @copyright Company Named Limited (c) 2025
*/
export class EntityManager {
/**
* Registered systems
* @readonly
* @type {System[]}
*/
readonly systems: System<any, any, any, any, any>[];
/**
* Current order of execution.
* Note: this can be smaller that the number of registered systems, as systems are only added to the execution order once their startup finishes
* @readonly
* @private
* @type {System[]}
*/
private readonly systemsExecutionOrder;
/**
* Observers associated with individual systems, responsible for {@link System.link}/{@link System.unlink}
* @readonly
* @private
* @type {Map<System,EntityObserver>}
*/
private readonly systemObservers;
/**
* @readonly
*/
readonly on: {
systemStarted: Signal<any, any, any, any, any, any, any, any>;
systemStopped: Signal<any, any, any, any, any, any, any, any>;
/**
* @type {Signal<System>}
*/
systemAdded: Signal<System<any, any, any, any, any>>;
systemRemoved: Signal<any, any, any, any, any, any, any, any>;
};
/**
*
* @type {EntityManagerState}
*/
state: EntityManagerState;
/**
* Track remainders of simulation time for fixed step
* Needed for accurate time keeping
* @private
* @readonly
* @type {Map<System, number>}
*/
private readonly systemAccumulatedFixedStepTime;
/**
* Value used to execute {@link System.fixedUpdate}
* In seconds.
* The default is ~60 Hz, which should be sufficient for most use-cases.
* Setting this value higher will reduce the total number of steps per second, and typically lead to better performance.
* Setting this value lower will increase number of steps per second, increasing simulation accuracy at the cost of performance.
* Make sure you understand the implications when modifying this.
* A good safe range is [0.001 - 0.2]
* @type {number}
*/
fixedUpdateStepSize: number;
/**
* How long can any given system run it's {@link System.fixedUpdate}, per simulation update
* This is value allows us to avoid cases where {@link System.fixedUpdate} takes longer that its time step and causes a runaway freeze
* In milliseconds.
* @type {number}
*/
fixedUpdatePerSystemExecutionTimeLimit: number;
/**
* Currently attached dataset.
* Do not modify directly, instead use {@link attachDataset} and {@link detachDataset} respectively.
* @type {EntityComponentDataset}
*/
dataset: EntityComponentDataset;
/**
* Whenever a system is added or removed, optimal execution plan changes, this flag tells us to rebuild the current plan
* see {@link #systemsExecutionOrder}
* @type {boolean}
* @private
*/
private __execution_order_needs_update;
/**
* Rebuild execution order
* @private
*/
private updateExecutionOrder;
/**
* Get list of all components referenced by active systems
* @returns {Class[]}
*/
getComponentTypeMap(): Class[];
/**
* Link a given dataset, will cause associated systems to work with the new dataset as well
* @param {EntityComponentDataset} dataset
* @throws {Error} if another dataset is attached
* @throws {Error} if dataset is incompatible with current system set
*/
attachDataset(dataset: EntityComponentDataset): void;
/**
* Dissociate currently bound dataset, will cause attached systems to unlink entities held in the dataset.
* Idempotent, if no dataset is attached - nothing will happen.
*/
detachDataset(): void;
/**
* @template T
* @param {Class<T>} systemClass
* @returns {boolean}
*/
hasSystem<T>(systemClass: Class<T>): boolean;
/**
* @template T
* @param {Class<T>} systemClass
* @returns {T|null}
*/
getSystem<T_1>(systemClass: Class<T_1>): T_1;
/**
* @deprecated use {@link EntityComponentDataset.getComponentClassByName} instead
* @template T
* @param {string} className
* @returns {null|Class<T>}
*/
getComponentClassByName<T_2>(className: string): null | Class<T_2>;
/**
* Advance simulation forward by a specified amount of time
* @param {number} timeDelta in seconds
*/
simulate(timeDelta: number): void;
/**
* If the {@link EntityManager} is already started, the system will be started automatically before being added
* @param {System} system
* @returns {Promise} resolution depends on {@link EntityManager}'s state, if running - promise resolves after system startup. Otherwise, the promise will be resolved immediately.
* @throws {IllegalStateException}
*/
addSystem(system: System<any, any, any, any, any>): Promise<any>;
/**
*
* @param {System} system
* @returns {Promise<boolean>}
*/
removeSystem(system: System<any, any, any, any, any>): Promise<boolean>;
/**
* @private
* @param {System} system
* @param {function(system: System)} successCallback
* @param {function(reason:*)} errorCallback
*/
private stopSystem;
/**
* @private
* @param {System} system
* @param {function(system: System)} successCallback
* @param {function(reason:*)} errorCallback
*/
private startSystem;
/**
* This method is asynchronous by nature, it has to wait for each system to finish its own startup.
* Make sure to register callback to be notified when the startup has finished
* @param {function} [readyCallback] executed once entity manager successfully completes startup
* @param {function} [errorCallback] executed if entity manager encounters an error during startup
*/
startup(readyCallback?: Function, errorCallback?: Function): void;
/**
*
* @param {Class} systemClass
* @returns {Promise.<System>}
*/
promiseSystem(systemClass: Class): Promise<System<any, any, any, any, any>>;
/**
* @param {Class} SystemClass
* @param {SystemState} state
* @returns {Promise.<System>}
*/
promiseSystemInState(SystemClass: Class, state: SystemState): Promise<System<any, any, any, any, any>>;
/**
* This method is asynchronous by nature, it will not be done until each system has finished its shutdown
* Make sure to use callback to be notified when the shutdown has completed
* @param {function} [readyCallback] Called when shutdown finishes successfully. defaults to no-operation
* @param {function} [errorCallback] Called when an error occurs during the shutdown process. defaults to console error output
*/
shutdown(readyCallback?: Function, errorCallback?: Function): void;
/**
* @deprecated use lowercase spelling `attachDataset` instead
*/
attachDataSet: (dataset: EntityComponentDataset) => void;
/**
* @deprecated use lowercase spelling `detachDataset` instead
*/
detachDataSet: () => void;
}
import { System } from "./System.js";
import Signal from "../../core/events/signal/Signal.js";
import { EntityComponentDataset } from "./EntityComponentDataset.js";
//# sourceMappingURL=EntityManager.d.ts.map