ecspresso
Version:
A minimal Entity-Component-System library for typescript and javascript.
5 lines (3 loc) • 10.2 kB
JavaScript
class Z{nextId=1;entities=new Map;componentIndices=new Map;addedCallbacks=new Map;removedCallbacks=new Map;createEntity(){let j=this.nextId++,G={id:j,components:{}};return this.entities.set(j,G),G}addComponent(j,G,H){let J=typeof j==="number"?this.entities.get(j):j;if(!J)throw new Error(`Entity ${j} does not exist`);if(J.components[G]=H,!this.componentIndices.has(G))this.componentIndices.set(G,new Set);this.componentIndices.get(G)?.add(J.id);let P=this.addedCallbacks.get(G);if(P)for(let X of P)X(H,J);return this}addComponents(j,G){let H=typeof j==="number"?this.entities.get(j):j;if(!H)throw new Error(`Entity ${j} does not exist`);for(let J in G)this.addComponent(H,J,G[J]);return this}removeComponent(j,G){let H=typeof j==="number"?this.entities.get(j):j;if(!H)throw new Error(`Entity ${j} does not exist`);let J=H.components[G];delete H.components[G];let P=this.removedCallbacks.get(G);if(P&&J!==void 0)for(let X of P)X(J,H);return this.componentIndices.get(G)?.delete(H.id),this}getComponent(j,G){let H=this.entities.get(j);if(!H)throw new Error(`Entity ${j} does not exist`);return H.components[G]||null}getEntitiesWithQuery(j=[],G=[]){if(j.length===0){if(G.length===0)return Array.from(this.entities.values());return Array.from(this.entities.values()).filter((P)=>{return G.every((X)=>!(X in P.components))})}let H=j.reduce((P,X)=>{let Y=this.componentIndices.get(X),g=Y?Y.size:0,w=this.componentIndices.get(P)?.size??1/0;return g<w?X:P},j[0]);return Array.from(this.componentIndices.get(H)||[]).filter((P)=>{let X=this.entities.get(P);return X&&j.every((Y)=>(Y in X.components))&&G.every((Y)=>!(Y in X.components))}).map((P)=>this.entities.get(P))}removeEntity(j){let G=typeof j==="number"?this.entities.get(j):j;if(!G)return!1;for(let H of Object.keys(G.components))this.componentIndices.get(H)?.delete(G.id);return this.entities.delete(G.id)}getEntity(j){return this.entities.get(j)}onComponentAdded(j,G){if(!this.addedCallbacks.has(j))this.addedCallbacks.set(j,new Set);return this.addedCallbacks.get(j).add(G),this}onComponentRemoved(j,G){if(!this.removedCallbacks.has(j))this.removedCallbacks.set(j,new Set);return this.removedCallbacks.get(j).add(G),this}}class _{handlers=new Map;subscribe(j,G){return this.addHandler(j,G,!1)}once(j,G){return this.addHandler(j,G,!0)}addHandler(j,G,H){if(!this.handlers.has(j))this.handlers.set(j,[]);let J={callback:G,once:H};return this.handlers.get(j).push(J),()=>{let P=this.handlers.get(j);if(P){let X=P.indexOf(J);if(X!==-1)P.splice(X,1)}}}publish(j,G){let H=this.handlers.get(j);if(!H)return;let J=[...H],P=[];for(let X of J)if(X.callback(G),X.once)P.push(X);if(P.length>0)for(let X of P){let Y=H.indexOf(X);if(Y!==-1)H.splice(Y,1)}}clear(){this.handlers.clear()}clearEvent(j){this.handlers.delete(j)}}class ${resources=new Map;resourceFactories=new Map;initializedResourceKeys=new Set;add(j,G){if(typeof G==="function"&&!/^class\s/.test(Function.prototype.toString.call(G)))this.resourceFactories.set(j,G);else this.resources.set(j,G),this.initializedResourceKeys.add(j);return this}get(j,G){let H=this.resources.get(j);if(H!==void 0)return H;let J=this.resourceFactories.get(j);if(J===void 0)throw new Error(`Resource ${String(j)} not found`);let P=J(G);if(!(P instanceof Promise))this.resources.set(j,P),this.initializedResourceKeys.add(j);return P}has(j){return this.resources.has(j)||this.resourceFactories.has(j)}remove(j){let G=this.resources.delete(j),H=this.resourceFactories.delete(j);if(this.initializedResourceKeys.has(j))this.initializedResourceKeys.delete(j);return G||H}getKeys(){let j=new Set([...this.resources.keys(),...this.resourceFactories.keys()]);return Array.from(j)}needsInitialization(j){return this.resourceFactories.has(j)&&!this.initializedResourceKeys.has(j)}getPendingInitializationKeys(){return Array.from(this.resourceFactories.keys()).filter((j)=>!this.initializedResourceKeys.has(j))}async initializeResource(j,G){if(!this.resourceFactories.has(j)||this.initializedResourceKeys.has(j))return;let J=await this.resourceFactories.get(j)(G);this.resources.set(j,J),this.initializedResourceKeys.add(j),this.resourceFactories.delete(j)}async initializeResources(j,...G){if(G.length===0){let H=this.getPendingInitializationKeys();await Promise.all(H.map((J)=>this.initializeResource(J,j)));return}await Promise.all(G.map((H)=>this.initializeResource(H,j)))}}class U{_label;_ecspresso;_bundle;queries={};processFunction;detachFunction;initializeFunction;eventHandlers;_priority=0;_isRegistered=!1;constructor(j,G=null,H=null){this._label=j;this._ecspresso=G;this._bundle=H}get label(){return this._label}get bundle(){return this._bundle}get ecspresso(){return this._ecspresso}_autoRegister(){if(this._isRegistered||!this._ecspresso)return;let j=this._buildSystemObject();D(j,this._ecspresso),this._isRegistered=!0}_buildSystemObject(){let j={label:this._label,entityQueries:this.queries,priority:this._priority};if(this.processFunction)j.process=this.processFunction;if(this.detachFunction)j.onDetach=this.detachFunction;if(this.initializeFunction)j.onInitialize=this.initializeFunction;if(this.eventHandlers)j.eventHandlers=this.eventHandlers;return j}setPriority(j){return this._priority=j,this}addQuery(j,G){let H=this;return H.queries={...this.queries,[j]:G},H}setProcess(j){return this.processFunction=j,this}registerAndContinue(){if(!this._ecspresso)throw new Error("Cannot register system: no ECSpresso instance attached");return this._autoRegister(),this._ecspresso}and(){if(!this._ecspresso)throw new Error("Cannot use and() method: no ECSpresso instance attached");return this._autoRegister(),this._ecspresso}setOnDetach(j){return this.detachFunction=j,this}setOnInitialize(j){return this.initializeFunction=j,this}setEventHandlers(j){return this.eventHandlers=j,this}build(j){let G={label:this._label,entityQueries:this.queries,priority:this._priority};if(this.processFunction)G.process=this.processFunction;if(this.detachFunction)G.onDetach=this.detachFunction;if(this.initializeFunction)G.onInitialize=this.initializeFunction;if(this.eventHandlers)G.eventHandlers=this.eventHandlers;if(this._ecspresso)D(G,this._ecspresso);if(j)D(G,j);return this}}function D(j,G){if(G._systems.push(j),G._sortSystems(),!j.eventHandlers)return;for(let H in j.eventHandlers){let J=j.eventHandlers[H]?.handler;J&&G.eventBus.subscribe(H,(P)=>{J(P,G)})}}function V(j,G){return new U(j,G)}function M(j,G){return new U(j,null,G)}var Q="0.4.1";var z={};class A{static VERSION=Q;_entityManager;_eventBus;_resourceManager;_systems=[];_sortedSystems=[];_installedBundles=new Set;constructor(){this._entityManager=new Z,this._eventBus=new _,this._resourceManager=new $,this._sortedSystems=[]}static create(){return new W}addSystem(j){return V(j,this)}update(j){for(let G of this._sortedSystems){if(!G.process)continue;let H={},J=!1,P=!1;if(G.entityQueries)for(let X in G.entityQueries){P=!0;let Y=G.entityQueries[X];if(Y){if(H[X]=this._entityManager.getEntitiesWithQuery(Y.with,Y.without||[]),H[X].length)J=!0}}if(J)G.process(H,j,this);else if(!P)G.process(z,j,this)}}async initialize(){await this.initializeResources();for(let j of this._systems)await j.onInitialize?.(this)}async initializeResources(...j){await this._resourceManager.initializeResources(this,...j)}_sortSystems(){this._sortedSystems=[...this._systems].sort((j,G)=>{let H=j.priority??0;return(G.priority??0)-H})}updateSystemPriority(j,G){let H=this._systems.find((J)=>J.label===j);if(!H)return!1;return H.priority=G,this._sortSystems(),!0}removeSystem(j){let G=this._systems.findIndex((J)=>J.label===j);if(G===-1)return!1;let H=this._systems[G];if(!H)return!1;if(H.onDetach)H.onDetach(this);return this._systems.splice(G,1),this._sortSystems(),!0}hasResource(j){return this._resourceManager.has(j)}getResource(j){let G=this._resourceManager.get(j,this);if(!G)throw new Error(`Resource "${j.toString()}" not found`);return G}addResource(j,G){return this._resourceManager.add(j,G),this}removeResource(j){return this._resourceManager.remove(j)}updateResource(j,G){let H=this.getResource(j),J=G(H);return this._resourceManager.add(j,J),this}getResourceKeys(){return this._resourceManager.getKeys()}resourceNeedsInitialization(j){return this._resourceManager.needsInitialization(j)}hasComponent(j,G){return this._entityManager.getComponent(j,G)!==null}spawn(j){let G=this._entityManager.createEntity();return this._entityManager.addComponents(G,j),G}getEntitiesWithQuery(j,G=[]){return this._entityManager.getEntitiesWithQuery(j,G)}get installedBundles(){return Array.from(this._installedBundles)}get entityManager(){return this._entityManager}get eventBus(){return this._eventBus}_installBundle(j){if(this._installedBundles.has(j.id))return this;this._installedBundles.add(j.id),j.registerSystemsWithEcspresso(this);let G=j.getResources();for(let[H,J]of G.entries())this._resourceManager.add(H,J);return this}}class W{ecspresso;constructor(){this.ecspresso=new A}withBundle(j){return this.ecspresso._installBundle(j),this}build(){return this.ecspresso}}function K(){return`bundle_${Date.now().toString(36)}_${Math.random().toString(36).substring(2,9)}`}class F{_systems=[];_resources=new Map;_id;constructor(j){this._id=j||K()}get id(){return this._id}set id(j){this._id=j}addSystem(j){if(typeof j==="string"){let G=M(j,this);return this._systems.push(G),G}else return this._systems.push(j),j}addResource(j,G){return this._resources.set(j,G),this}getSystems(){return this._systems.map((j)=>j.build())}registerSystemsWithEcspresso(j){for(let G of this._systems)G.build(j)}getResources(){return new Map(this._resources)}getResource(j){return this._resources.get(j)}getSystemBuilders(){return[...this._systems]}hasResource(j){return this._resources.has(j)}}function f(j,...G){if(G.length===0)return new F(j);let H=new F(j);for(let J of G){for(let P of J.getSystemBuilders())H.addSystem(P);for(let[P,X]of J.getResources().entries())H.addResource(P,X)}return H}function b(j){return j}var r=A;export{f as mergeBundles,r as default,b as createQueryDefinition,U as SystemBuilder,$ as ResourceManager,_ as EventBus,Z as EntityManager,F as Bundle};
//# debugId=186F2921EE95DCD564756E2164756E21
//# sourceMappingURL=index.js.map