@curbl/ecs
Version:
Small Entity Component System
3 lines (2 loc) • 8.11 kB
JavaScript
import{v4 as t}from"uuid";class e{constructor(t,e){this.mask=void 0,this.mask=new Uint32Array(Math.ceil(t/32)),void 0!==e&&this.mask.set(e)}set(t,e){const s=this.mask.length-(1+(t>>>5));this.mask[s]=0===e?(this.mask[s]|1<<t)^1<<t:this.mask[s]|1<<t}compareAnd(t){this.balance(t);for(let e=0;e<this.mask.length;e++)if(this.mask[e]!==(this.mask[e]&t.mask[e])>>>0)return!1;return!0}isEqual(t){this.balance(t);for(let e=0;e<this.mask.length;e++)if(this.mask[e]!==t.mask[e])return!1;return!0}balance(t){this.mask.length!==t.mask.length&&(this.mask.length>t.mask.length?t.grow(this.mask.length):this.grow(t.mask.length))}grow(t){const e=new Uint32Array(t);e.set(this.mask,(t||this.mask.length)-this.mask.length),this.mask=e}clone(){return new e(32*this.mask.length,this.mask)}clear(){for(let t=0;t<this.mask.length;t++)this.mask[t]=0}toString(){let t="";for(let e=0;e<this.mask.length;e++){const s=this.mask[e].toString(2);t+="00000000000000000000000000000000".substr(0,32-s.length)+s}return t}}class s{constructor(){this.components=void 0,this.size=void 0,this.components=Object.create(null),this.size=0}clear(){this.components=Object.create(null),this.size=0}register(t){return void 0===this.components[t]&&(this.components[t]=this.size,this.size++),this.components[t]}remove(t){void 0!==this.components[t]&&(delete this.components[t],this.size=Object.keys(this.components).length)}buildMask(t){const s=new e(this.size);for(let e,i=0;e=t[i];i++)s.set("string"==typeof e?this.components[e]:this.components[e.__id],1);return s}}class i{constructor(t,s){this.__id=void 0,this.__bitmask=void 0,this.dead=void 0,this.dirty=void 0,this.paused=void 0,this.store=void 0,this.components=void 0,this.updates=void 0,this.removedComponents=void 0,this.__id=t,this.__bitmask=new e(32),this.store=s,this.components=new Map,this.updates=new Map,this.removedComponents=[],this.dirty=!1,this.dead=!1,this.paused=!1}addComponent(t){this.updates.set(t.constructor.__id,{component:t,added:!0}),this.markDirty()}add(t){if(!this.dead){const e=t;e.load?e.load().then(()=>this.addComponent(e)):this.addComponent(e)}}get(t){return this.components.get("string"==typeof t?t:t.__id)}has(t){return this.components.has("string"==typeof t?t:t.__id)}removeComponent(t){this.components.has(t)?(this.updates.set(t,{component:this.components.get(t),added:!1}),this.markDirty()):this.updates.delete(t)}remove(t){const e="string"==typeof t?t:t.__id;if(!this.dead&&(this.components.has(e)||this.updates.has(e))){const t=this.components.get(e);t&&t.unload?t.unload().then(()=>this.removeComponent(e)):this.removeComponent(e)}}dispose(){this.dead=!0,this.markDirty()}active(){return this.store.active(this)}pause(){this.paused||(this.markDirty(),this.paused=!0)}unpause(){this.paused&&(this.paused=!1,this.store.add(this),this.markDirty())}__updateRemoved(){if(this.dead)return this.__clear(),void this.store.delete(this);if(this.paused)this.store.remove(this);else{for(let t,e=0;t=this.removedComponents[e];e++)this.components.delete(t.constructor.__id);this.removedComponents.length=0}}__updateMaskAndNew(){if(!this.dirty)return;if(this.dead||this.paused)return this.__bitmask.clear(),void(this.dirty=!1);const t=this.updates.values();for(const e of t)e.added?this.__add(e.component):e.component&&(this.__bitmask.set(e.component.constructor.__bit,0),this.removedComponents.push(e.component));this.updates.clear(),this.dirty=!1}markDirty(){this.dirty||this.paused||(this.dirty=!0,this.store.markModified(this))}__add(t){this.__bitmask.set(t.constructor.__bit,1),this.components.set(t.constructor.__id,t)}__clear(){this.__bitmask.clear(),this.components.clear(),this.updates.clear(),this.removedComponents.length=0,this.dirty=!1,this.dead=!1,this.paused=!1}}class o{constructor(){this.queries=new Map}registerQuery(t,e){for(const t of this.queries.keys())if(t.isEqual(e))return[this.queries.get(t).list,t];const s={set:new Set,list:[],onEntityAdded:[],onEntityRemoved:[]};for(const i of t)e.compareAnd(i.__bitmask)&&(s.set.add(i),s.list.push(i));return this.queries.set(e,s),[s.list,e]}addQueryOnAdded(t,e){var s;null==(s=this.queries.get(t))||s.onEntityAdded.push(e)}addQueryOnRemoved(t,e){var s;null==(s=this.queries.get(t))||s.onEntityRemoved.push(e)}static callEntityAdded(t,e){for(let s,i=0;s=e.onEntityAdded[i];i++)s.onEntityAdded(t)}static callEntityRemoved(t,e){for(let s,i=0;s=e.onEntityRemoved[i];i++)s.onEntityRemoved(t)}static updateQuery(t,e,s){const i=e.compareAnd(t.__bitmask),n=s.set.has(t);return i&&!n?(s.set.add(t),o.callEntityAdded(t,s),!0):!(i||!n||(s.set.delete(t),o.callEntityRemoved(t,s),0))}update(t){for(const[e,s]of this.queries.entries()){let i=!1;for(let n,r=0;n=t[r];r++)n.__updateMaskAndNew(),i=o.updateQuery(n,e,s)||i;if(i){s.list.length=0;for(const t of s.set.values())s.list.push(t)}}for(let e,s=0;e=t[s];s++)e.__updateRemoved()}clear(){const t=this.queries.values();for(const e of t)e.set.clear(),e.list.length=0}}class n{constructor(){this.queryStore=new o,this.entities=new Map,this.pool=[],this.maxPoolSize=1e4,this.modified=[]}setMaxPoolSize(t){this.maxPoolSize=t,this.pool.length>this.maxPoolSize&&(this.pool.length=this.maxPoolSize)}registerQuery(t){return this.queryStore.registerQuery(this.entities.values(),t)}addQueryOnAdded(t,e){this.queryStore.addQueryOnAdded(t,e)}addQueryOnRemoved(t,e){this.queryStore.addQueryOnRemoved(t,e)}create(e){const s=this.pool.pop()||new i(t(),this);this.entities.set(s.__id,s);for(let t,i=0;t=e[i];i++)s.add(t);return s}active(t){return this.entities.has(t.__id)}add(t){this.entities.set(t.__id,t)}delete(t){this.entities.delete(t.__id),this.pool.length<this.maxPoolSize&&this.pool.push(t)}remove(t){this.entities.delete(t.__id)}markModified(t){this.modified.push(t)}update(){if(!this.modified.length)return;const t=[...this.modified];this.queryStore.update(t),this.modified=this.modified.slice(t.length,this.modified.length)}clear(){this.modified.length=0,this.entities.clear(),this.queryStore.clear()}}function r(){}class h{setUp(){}tearDown(){}entities(){return this.constructor.__entities}}function d(t,e){return function(t,e){for(let s,i=0;s=e[i];i++)t.constructor&&t.constructor.prototype?null==t.constructor.prototype[s]&&(t.constructor.prototype[s]=r):null==t[s]&&(t[s]=r)}(t,e),t}class a{constructor(){this.updateMethods=["update"],this.systems=[]}setUpdateMethods(t){this.updateMethods=t}addSystem(t){this.hasSystem(t)||(this.systems.push(t),d(t,this.updateMethods),t.setUp())}removeSystem(t){const e=this.systems.indexOf(t);-1!==e&&(this.systems.splice(e,1),t.tearDown())}hasSystem(t){return this.systems.includes(t)}clear(){this.systems.length=0,this.updateMethods=["update"]}callMethodOnSystems(t,e,s,i,o,n,r,h,d,a){for(let m,c=0;m=this.systems[c];c++)m[t](e,s,i,o,n,r,h,d,a)}update(t,e,s,i,o,n,r,h,d){for(let a,m=0;a=this.updateMethods[m];m++)this.callMethodOnSystems(a,t,e,s,i,o,n,r,h,d)}}class m{constructor(){this.entityStore=void 0,this.systemStore=void 0,this.componentBitMask=void 0,this.entityStore=new n,this.systemStore=new a,this.componentBitMask=new s}setMaxEntityPoolSize(t){this.entityStore.setMaxPoolSize(t)}setUpdateMethods(t){this.systemStore.setUpdateMethods(t)}reset(){this.systemStore.clear(),this.entityStore.clear()}addEntity(...t){return this.entityStore.create(t)}addSystem(t){this.systemStore.addSystem(t)}active(t){return this.entityStore.active(t)}removeSystem(t){this.systemStore.removeSystem(t)}hasSystem(t){return this.systemStore.hasSystem(t)}Component(t){const e=this.componentBitMask.register(t);return function(s){return s.__id=t,s.__bit=e,s}}System(...t){for(let e,s=0;e=t[s];s++)this.componentBitMask.register("string"==typeof e?e:e.__id);const e=this.componentBitMask.buildMask(t),[s,i]=this.entityStore.registerQuery(e),o=this.entityStore;return function(t){return t.__entities=s,class extends t{constructor(...t){super(...t),this.onEntityAdded&&o.addQueryOnAdded(i,this),this.onEntityRemoved&&o.addQueryOnRemoved(i,this)}}}}update(t,e,s,i,o,n,r,h,d){this.entityStore.update(),this.systemStore.update(t,e,s,i,o,n,r,h,d)}}export{m as ECS,i as EntityHandle,h as System,d as injectSystem};
//# sourceMappingURL=ecs.modern.js.map