UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

161 lines (129 loc) 4.51 kB
import { IllegalStateException } from "../../core/fsm/exceptions/IllegalStateException.js"; import { SerializationMetadata } from "../ecs/components/SerializationMetadata.js"; import Entity from "../ecs/Entity.js"; import { EntityFlags } from "../ecs/EntityFlags.js"; import { ControlContextState } from "./ControlContextState.js"; export class ControlContext { /** * @private * @type {EntityComponentDataset} */ ecd = null; /** * @private * @type {Entity[]} */ entities = []; /** * @private * @type {ControlContextState|number} */ state = ControlContextState.Initial; /** * Should entities be made transient or not, transient entities do not get persisted * @private * @type {boolean} */ transientEntities = true; /** * * @returns {ControlContextState|number} */ getState() { return this.state; } /** * Do not invoke "build" manually * @returns {Entity} */ makeEntity() { const eb = new Entity(); if (this.transientEntities) { eb.add(SerializationMetadata.Transient); } this.entities.push(eb); if (this.state === ControlContextState.Running) { eb.build(this.ecd); } return eb; } /** * Initialization method is called once before the context is used for the first time * @param {EntityComponentDataset} ecd */ initialize(ecd) { if (this.state === ControlContextState.Ready && this.ecd === ecd) { //already in the right state return; } if (this.state !== ControlContextState.Initial && this.state !== ControlContextState.Disposed) { throw new IllegalStateException(`Expected state to be INITIAL(${ControlContextState.Initial}) or DISPOSED(${ControlContextState.Disposed}), instead got ${this.state}`); } this.ecd = ecd; //this should be extended in subclasses this.state = ControlContextState.Ready; } /** * Disposal is done when the context is no longer needed, any used resources should be freed here */ dispose() { if (this.state === ControlContextState.Disposed) { //already in the right state return; } if (this.state === ControlContextState.Initial) { //nothing to do } else { if (this.state === ControlContextState.Running) { this.shutdown(); } if (this.state !== ControlContextState.Ready) { throw new IllegalStateException(`Expected READY(${ControlContextState.Ready}) state, instead was ${this.state}`); } } this.ecd = null; //override in subclasses this.state = ControlContextState.Disposed; } /** * Invoked to make context active * @throws IllegalStateException */ startup() { if (this.state === ControlContextState.Running) { //already in the right state return; } if (this.state !== ControlContextState.Ready) { throw new IllegalStateException(`Expected READY(${ControlContextState.Ready}) state, instead was ${this.state}`); } for (const e of this.entities) { if (e.getFlag(EntityFlags.Built)) { throw new IllegalStateException(`Entity ${e.id} is already built, this violates pre-condition of control context`); } e.build(this.ecd) } this.state = ControlContextState.Running; } /** * Invoked to deactivate context * @throws IllegalStateException */ shutdown() { if (this.state === ControlContextState.Ready) { //already in the right state return; } if (this.state !== ControlContextState.Running) { throw new IllegalStateException(`Expected RUNNING(${ControlContextState.Running}) state, instead was ${this.state}`); } for (const e of this.entities) { if (!e.getFlag(EntityFlags.Built)) { //entity is not built, skip continue; } e.destroy(); } this.state = ControlContextState.Ready; } }