ecsjs 1.4.0-beta.4 → 1.4.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # 1.4.0-beta.5
2
+
3
+ - Added entity id reclaiming to [EntityMap](https://ecsjs.gitlab.io/ecs/classes/EntityMap.html)
4
+ - Destroyed entity IDs are now reused to maintain density and avoid ID exhaustion.
5
+
6
+ - Improved [EntityMap.parse](https://ecsjs.gitlab.io/ecs/classes/EntityMap.html#parse)
7
+ - Correctly restores internal state including `nextId` and `freeIds`.
8
+
9
+ - Improved code documentation for `EntityMap` and `ComponentQuery`.
10
+
1
11
  # 1.4.0-beta.4
2
12
 
3
13
  - Improved code documentation
package/dist/ecs.js CHANGED
@@ -1,2 +1,2 @@
1
- var l="ComponentMap",y="ComponentClassesMap";function T(o){let e=0;for(let t=0;t<o.length;t++){let n=o.charCodeAt(t);e=(e<<5)-e+n,e|=0}return e}var p=class{hashIdToName=new Map;hashIdToIndex=new Map;indexToHashId=[];maps=[];constructor(e){if(e)for(let t=0;t<e.length;t++){let n=e[t];this.setByHashId(n[0],n[1])}}get size(){return this.maps.length}clear(){this.maps.length=0,this.indexToHashId.length=0,this.hashIdToIndex.clear()}get(e){let t=this.hashIdToIndex.get(e.hashId);return t!==void 0?this.maps[t]:void 0}set(e,t){return e.hashId===void 0&&(e.hashId=T(e.name)),this.hashIdToName.set(e.hashId,e.name),this.setByHashId(e.hashId,t)}setByHashId(e,t){let n=this.hashIdToIndex.get(e);return n!==void 0?this.maps[n]=t:(this.hashIdToIndex.set(e,this.maps.length),this.indexToHashId.push(e),this.maps.push(t)),this}delete(e){let t=e.hashId,n=this.hashIdToIndex.get(t);if(n===void 0)return!1;let s=this.maps.length-1,r=this.indexToHashId[s];return this.maps[n]=this.maps[s],this.indexToHashId[n]=r,this.hashIdToIndex.set(r,n),this.maps.pop(),this.indexToHashId.pop(),this.hashIdToIndex.delete(t),!0}forEach(e){for(let t=0;t<this.maps.length;t++)e(this.maps[t],this.hashIdToName.get(this.indexToHashId[t]))}values(){return this.maps.values()}entries(){let e=0,t=this.maps,n=this.indexToHashId;return{next(){if(e<t.length){let s=[n[e],t[e]];return e++,{value:s,done:!1}}return{value:void 0,done:!0}},reset(){e=0},[Symbol.iterator](){return this}}}toJSON(){return{[y]:1,iterable:[...this.entries()]}}};var m=class{indices=[];entities=[];instances=[];constructor(e){if(e)for(let t=0;t<e.length;t++){let n=e[t];this.set(n[0],n[1])}}get size(){return this.instances.length}clear(){this.indices=[],this.entities.length=0,this.instances.length=0}set(e,t){if(this.has(e)){this.instances[this.indices[e]]=t;return}this.indices[e]=this.instances.length,this.entities.push(e),this.instances.push(t)}get(e){let t=this.indices[e];return t!==void 0&&this.entities[t]===e?this.instances[t]:void 0}delete(e){let t=this.indices[e];if(t===void 0||t===-1||this.entities[t]!==e)return!1;let n=this.instances.length-1,s=this.entities[n];return this.instances[t]=this.instances[n],this.entities[t]=s,this.indices[s]=t,this.instances.pop(),this.entities.pop(),this.indices[e]=-1,!0}has(e){let t=this.indices[e];return t!==void 0&&t!==-1&&this.entities[t]===e}forEach(e){for(let t=0;t<this.instances.length;t++)e(this.instances[t],this.entities[t])}firstEntry(){return this.entities.length===0?void 0:[this.entities[0],this.instances[0]]}firstKey(){return this.entities.length===0?void 0:this.entities[0]}firstValue(){return this.instances.length===0?void 0:this.instances[0]}[Symbol.iterator](){return this.entries()}keys(){return this.entities.values()}values(){return this.instances.values()}entries(){let e=0,t=this.entities,n=this.instances;return{next(){if(e<n.length){let s={value:[t[e],n[e]],done:!1};return e++,s}return{value:void 0,done:!0}},reset(){e=0},[Symbol.iterator](){return this}}}toJSON(){return{[l]:1,iterable:[...this.entries()]}}toTable(){let e=[];for(let[t,n]of this.entries()){let s=n,r={};r["entity.key"]=t,r["entity.type"]=s.constructor.name,e.push({...r,...s})}return e}printTable(e=[]){return console.table(this.toTable(),e),this}};var c=class extends Error{constructor(){super("Component type is missing the 'name' parameter. i.e. a constructor name")}},i=class extends Error{constructor(t){super(`Component map does not exist for '${t}'`);this.componentName=t}};var a=class{keyMap;componentMaps=[];entries;constructor(e){this.keyMap=e.keyMap,this.componentMaps=e.componentMaps,this.entries=this.keyMap.entries()}next(){let e=this.entries.next(),{value:t,done:n}=e;if(n)return{value:t,done:n};let s=t[0];for(let r=0;r<this.componentMaps.length;r++){let h=this.componentMaps[r];t.push(h.get(s))}return{value:t,done:!1}}reset(){this.entries=this.keyMap.entries()}[Symbol.iterator](){return this}};var u=class{constructor(e,...t){this.ecs=e;this.keyMap=this.ecs.getMap(t[0]);for(let n=1;n<t.length;n++)this.componentMaps.push(this.ecs.getMap(t[n]))}keyMap;componentMaps=[];firstEntry(){if(this.componentMaps.length===0)return this.keyMap.firstEntry();let[e,t]=this.keyMap.firstEntry()??[];if(e===void 0)return;let n=[e,t];for(let s=0;s<this.componentMaps.length;s++)n.push(this.componentMaps[s].get(e));return n}firstKey(){let e=this.keyMap.firstKey();if(this.componentMaps.length===0)return e;if(e===void 0)return;let t=[e];for(let n=0;n<this.componentMaps.length;n++)t.push(this.componentMaps[n].get(e));return t}firstValue(){if(this.componentMaps.length===0)return this.keyMap.firstValue();let[e,t]=this.keyMap.firstEntry()??[];if(e===void 0)return;let n=[t];for(let s=0;s<this.componentMaps.length;s++)n.push(this.componentMaps[s].get(e));return n}get entityCount(){return this.keyMap.size}destroyEntities(){return this.ecs.destroyEntity(...this.keyMap.keys())}keys(){return this.keyMap.keys()}values(){let e=this.keyMap,t=this.componentMaps,n=e.keys();return{next(){let s=n.next();if(s.done)return{value:void 0,done:!0};let r=s.value,C=[e.get(r)];for(let f=0;f<t.length;f++){let I=t[f];C.push(I.get(r))}return{value:C,done:!1}},reset(){n=e.keys()},[Symbol.iterator](){return this}}}entries(){return this[Symbol.iterator]()}[Symbol.iterator](){return new a(this)}};var d=class o{components=new p;nextId=0;register(...e){for(let t of e){if(t.name===void 0)throw new c;this.components.set(t,new m)}return this}getMap(e){let t=this.components.get(e);if(t===void 0)throw new i(e.name);return t}first(e){return this.firstEntity(e)}firstEntity(e){let t=this.getMap(e)?.firstKey();if(t!==void 0)return this.get(t)}entityValues(e){let t=this.getMap(e)?.keys();if(t!==void 0)return[...t].map(n=>this.get(n))}firstEntry(e,...t){return t.length===0?this.getMap(e)?.firstEntry():this.firstKey(e,e,...t)}firstKey(e,...t){let n=this.getMap(e)?.firstKey();if(arguments.length===1)return n;if(n!==void 0)return[n,...t.map(s=>this.getEntity(n,s))]}firstValue(e,...t){if(arguments.length===1)return this.getMap(e)?.firstValue();let[n,s]=this.getMap(e)?.firstEntry()??[];if(n!==void 0)return[s,...t.map(r=>this.getEntity(n,r))]}getEntity(e,t){let n=this.components.get(t);if(n===void 0)throw new i(t.name);return n.get(e)}get(e,...t){return t.length===1?this.getEntity(e,t[0]):t.length>1?t.map(n=>this.getEntity(e,n)):[...this.components.values()].filter(n=>n.has(e)).map(n=>n.get(e))}has(e,t){let n=this.components.get(t);return n===void 0?!1:n.has(e)}hasAll(e,...t){for(let n=0;n<t.length;n++){let s=t[n],r=this.components.get(s);if(r===void 0||r.has(e)===!1)return!1}return!0}hasAny(e,...t){for(let n=0;n<t.length;n++){let s=t[n],r=this.components.get(s);if(r!==void 0&&r.has(e))return!0}return!1}setEntity(e,t){let n=this.components.get(t.constructor);if(n===void 0)throw new i(t.constructor.name);return n.set(e,t),t}set(e,...t){return t.length>1?t.map(n=>this.setEntity(e,n)):this.setEntity(e,t[0])}remove(e,...t){for(let n of t)this.removeByKey(e,n)}removeByKey(e,t){let n=this.components.get(t);if(n===void 0)throw new i(t.name);return n.get(e)===void 0?!1:n.delete(e)}destroyEntity(...e){let t=0;for(let n=0;n<e.length;n++){let s=e[n];for(let r of this.components.values())r.has(s)&&(r.delete(s),t++)}return t}getNextId(){return this.nextId++,this.nextId}clear(){return this.components.clear(),this.nextId=0,this}clearComponents(){return this.components.forEach(e=>e.clear()),this.nextId=0,this}iterator(e,...t){return new a(new u(this,e,...t))}query(e,...t){return new u(this,e,...t)}printTable(e=[],t=[]){return this.components.forEach((n,s)=>{(e.length===0||e.includes(s))&&console.table(n.toTable(),t)}),this}printEntity(e,t=[]){for(let n of this.components.values()){if(n.has(e)===!1)continue;let s=n.get(e),r={"entity.type":s.constructor.name,...s};console.table({[e]:r},t)}return this}static parse(e){return JSON.parse(e,function(n,s){return s.hasOwnProperty("components")?(Reflect.setPrototypeOf(s,o.prototype),s):s.hasOwnProperty(l)?new m(s.iterable):s.hasOwnProperty(y)?new p(s.iterable):this[n]})}static createWithTracing(e=[]){let t={get(n,s){let r=n[s];return typeof r=="function"&&(e.length===0||e.includes(s))?function(...h){return console.groupCollapsed("ecs trace",s,h),console.trace(),console.groupEnd(),r.apply(this,h)}:r}};return new Proxy(new o,t)}};var g=new d;typeof window<"u"?window.ecs=g:typeof module<"u"&&module!==null&&(module.exports={ecs:g});export{p as ComponentClassesMap,a as ComponentIterator,m as ComponentMap,u as ComponentQuery,d as EntityMap,g as ecs};
1
+ var l="ComponentMap",y="ComponentClassesMap";function T(o){let e=0;for(let t=0;t<o.length;t++){let n=o.charCodeAt(t);e=(e<<5)-e+n,e|=0}return e}var m=class{hashIdToName=new Map;hashIdToIndex=new Map;indexToHashId=[];maps=[];constructor(e){if(e)for(let t=0;t<e.length;t++){let n=e[t];this.setByHashId(n[0],n[1])}}get size(){return this.maps.length}clear(){this.maps.length=0,this.indexToHashId.length=0,this.hashIdToIndex.clear()}get(e){let t=this.hashIdToIndex.get(e.hashId);return t!==void 0?this.maps[t]:void 0}set(e,t){return e.hashId===void 0&&(e.hashId=T(e.name)),this.hashIdToName.set(e.hashId,e.name),this.setByHashId(e.hashId,t)}setByHashId(e,t){let n=this.hashIdToIndex.get(e);return n!==void 0?this.maps[n]=t:(this.hashIdToIndex.set(e,this.maps.length),this.indexToHashId.push(e),this.maps.push(t)),this}delete(e){let t=e.hashId,n=this.hashIdToIndex.get(t);if(n===void 0)return!1;let s=this.maps.length-1,r=this.indexToHashId[s];return this.maps[n]=this.maps[s],this.indexToHashId[n]=r,this.hashIdToIndex.set(r,n),this.maps.pop(),this.indexToHashId.pop(),this.hashIdToIndex.delete(t),!0}forEach(e){for(let t=0;t<this.maps.length;t++)e(this.maps[t],this.hashIdToName.get(this.indexToHashId[t]))}values(){return this.maps.values()}entries(){let e=0,t=this.maps,n=this.indexToHashId;return{next(){if(e<t.length){let s=[n[e],t[e]];return e++,{value:s,done:!1}}return{value:void 0,done:!0}},reset(){e=0},[Symbol.iterator](){return this}}}toJSON(){return{[y]:1,iterable:[...this.entries()]}}};var u=class{indices=[];entities=[];instances=[];constructor(e){if(e)for(let t=0;t<e.length;t++){let n=e[t];this.set(n[0],n[1])}}get size(){return this.instances.length}clear(){this.indices=[],this.entities.length=0,this.instances.length=0}set(e,t){if(this.has(e)){this.instances[this.indices[e]]=t;return}this.indices[e]=this.instances.length,this.entities.push(e),this.instances.push(t)}get(e){let t=this.indices[e];return t!==void 0&&this.entities[t]===e?this.instances[t]:void 0}delete(e){let t=this.indices[e];if(t===void 0||t===-1||this.entities[t]!==e)return!1;let n=this.instances.length-1,s=this.entities[n];return this.instances[t]=this.instances[n],this.entities[t]=s,this.indices[s]=t,this.instances.pop(),this.entities.pop(),this.indices[e]=-1,!0}has(e){let t=this.indices[e];return t!==void 0&&t!==-1&&this.entities[t]===e}forEach(e){for(let t=0;t<this.instances.length;t++)e(this.instances[t],this.entities[t])}firstEntry(){return this.entities.length===0?void 0:[this.entities[0],this.instances[0]]}firstKey(){return this.entities.length===0?void 0:this.entities[0]}firstValue(){return this.instances.length===0?void 0:this.instances[0]}[Symbol.iterator](){return this.entries()}keys(){return this.entities.values()}values(){return this.instances.values()}entries(){let e=0,t=this.entities,n=this.instances;return{next(){if(e<n.length){let s={value:[t[e],n[e]],done:!1};return e++,s}return{value:void 0,done:!0}},reset(){e=0},[Symbol.iterator](){return this}}}toJSON(){return{[l]:1,iterable:[...this.entries()]}}toTable(){let e=[];for(let[t,n]of this.entries()){let s=n,r={};r["entity.key"]=t,r["entity.type"]=s.constructor.name,e.push({...r,...s})}return e}printTable(e=[]){return console.table(this.toTable(),e),this}};var f=class extends Error{constructor(){super("Component type is missing the 'name' parameter. i.e. a constructor name")}},a=class extends Error{constructor(t){super(`Component map does not exist for '${t}'`);this.componentName=t}};var p=class{keyMap;componentMaps=[];entries;constructor(e){this.keyMap=e.keyMap,this.componentMaps=e.componentMaps,this.entries=this.keyMap.entries()}next(){let e=this.entries.next(),{value:t,done:n}=e;if(n)return{value:t,done:n};let s=t[0];for(let r=0;r<this.componentMaps.length;r++){let i=this.componentMaps[r];t.push(i.get(s))}return{value:t,done:!1}}reset(){this.entries=this.keyMap.entries()}[Symbol.iterator](){return this}};var h=class{constructor(e,...t){this.ecs=e;this.keyMap=this.ecs.getMap(t[0]);for(let n=1;n<t.length;n++)this.componentMaps.push(this.ecs.getMap(t[n]))}keyMap;componentMaps=[];firstEntry(){if(this.componentMaps.length===0)return this.keyMap.firstEntry();let[e,t]=this.keyMap.firstEntry()??[];if(e===void 0)return;let n=[e,t];for(let s=0;s<this.componentMaps.length;s++)n.push(this.componentMaps[s].get(e));return n}firstKey(){let e=this.keyMap.firstKey();if(this.componentMaps.length===0)return e;if(e===void 0)return;let t=[e];for(let n=0;n<this.componentMaps.length;n++)t.push(this.componentMaps[n].get(e));return t}firstValue(){if(this.componentMaps.length===0)return this.keyMap.firstValue();let[e,t]=this.keyMap.firstEntry()??[];if(e===void 0)return;let n=[t];for(let s=0;s<this.componentMaps.length;s++)n.push(this.componentMaps[s].get(e));return n}get entityCount(){return this.keyMap.size}destroyEntities(){return this.ecs.destroyEntity(...this.keyMap.keys())}keys(){return this.keyMap.keys()}values(){let e=this.keyMap,t=this.componentMaps,n=e.keys();return{next(){let s=n.next();if(s.done)return{value:void 0,done:!0};let r=s.value,C=[e.get(r)];for(let c=0;c<t.length;c++){let I=t[c];C.push(I.get(r))}return{value:C,done:!1}},reset(){n=e.keys()},[Symbol.iterator](){return this}}}entries(){return this[Symbol.iterator]()}[Symbol.iterator](){return new p(this)}};var d=class o{components=new m;nextId=0;freeIds=[];register(...e){for(let t of e){if(t.name===void 0)throw new f;this.components.set(t,new u)}return this}getMap(e){let t=this.components.get(e);if(t===void 0)throw new a(e.name);return t}first(e){return this.firstEntity(e)}firstEntity(e){let t=this.getMap(e)?.firstKey();if(t!==void 0)return this.get(t)}entityValues(e){let t=this.getMap(e)?.keys();if(t!==void 0)return[...t].map(n=>this.get(n))}firstEntry(e,...t){return t.length===0?this.getMap(e)?.firstEntry():this.firstKey(e,e,...t)}firstKey(e,...t){let n=this.getMap(e)?.firstKey();if(arguments.length===1)return n;if(n!==void 0)return[n,...t.map(s=>this.getEntity(n,s))]}firstValue(e,...t){if(arguments.length===1)return this.getMap(e)?.firstValue();let[n,s]=this.getMap(e)?.firstEntry()??[];if(n!==void 0)return[s,...t.map(r=>this.getEntity(n,r))]}getEntity(e,t){let n=this.components.get(t);if(n===void 0)throw new a(t.name);return n.get(e)}get(e,...t){return t.length===1?this.getEntity(e,t[0]):t.length>1?t.map(n=>this.getEntity(e,n)):[...this.components.values()].filter(n=>n.has(e)).map(n=>n.get(e))}has(e,t){let n=this.components.get(t);return n===void 0?!1:n.has(e)}hasAll(e,...t){for(let n=0;n<t.length;n++){let s=t[n],r=this.components.get(s);if(r===void 0||r.has(e)===!1)return!1}return!0}hasAny(e,...t){for(let n=0;n<t.length;n++){let s=t[n],r=this.components.get(s);if(r!==void 0&&r.has(e))return!0}return!1}setEntity(e,t){let n=this.components.get(t.constructor);if(n===void 0)throw new a(t.constructor.name);return n.set(e,t),t}set(e,...t){return t.length>1?t.map(n=>this.setEntity(e,n)):this.setEntity(e,t[0])}remove(e,...t){for(let n of t)this.removeByKey(e,n)}removeByKey(e,t){let n=this.components.get(t);if(n===void 0)throw new a(t.name);return n.get(e)===void 0?!1:n.delete(e)}destroyEntity(...e){let t=0;for(let n=0;n<e.length;n++){let s=e[n],r=!1;for(let i of this.components.values())i.has(s)&&(i.delete(s),t++,r=!0);r&&this.freeIds.push(s)}return t}getNextId(){let e=this.freeIds.pop();return e!==void 0?e:(this.nextId++,this.nextId)}clear(){return this.components.clear(),this.nextId=0,this.freeIds.length=0,this}clearComponents(){return this.components.forEach(e=>e.clear()),this.nextId=0,this.freeIds.length=0,this}iterator(e,...t){return new p(new h(this,e,...t))}query(e,...t){return new h(this,e,...t)}printTable(e=[],t=[]){return this.components.forEach((n,s)=>{(e.length===0||e.includes(s))&&console.table(n.toTable(),t)}),this}printEntity(e,t=[]){for(let n of this.components.values()){if(n.has(e)===!1)continue;let s=n.get(e),r={"entity.type":s.constructor.name,...s};console.table({[e]:r},t)}return this}static parse(e){return JSON.parse(e,function(n,s){return s.hasOwnProperty("components")?(Reflect.setPrototypeOf(s,o.prototype),s):s.hasOwnProperty("nextId")||s.hasOwnProperty("freeIds")?s:s.hasOwnProperty(l)?new u(s.iterable):s.hasOwnProperty(y)?new m(s.iterable):this[n]})}static createWithTracing(e=[]){let t={get(n,s){let r=n[s];return typeof r=="function"&&(e.length===0||e.includes(s))?function(...i){return console.groupCollapsed("ecs trace",s,i),console.trace(),console.groupEnd(),r.apply(this,i)}:r}};return new Proxy(new o,t)}};var g=new d;typeof window<"u"?window.ecs=g:typeof module<"u"&&module!==null&&(module.exports={ecs:g});export{m as ComponentClassesMap,p as ComponentIterator,u as ComponentMap,h as ComponentQuery,d as EntityMap,g as ecs};
2
2
  //# sourceMappingURL=ecs.js.map
package/dist/ecs.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/types.ts", "../src/utils.ts", "../src/component-classes.ts", "../src/component-map.ts", "../src/errors.ts", "../src/iterator.ts", "../src/query.ts", "../src/entity-map.ts", "../src/ecs.ts"],
4
- "sourcesContent": ["/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n/**\n * Property key used for ComponentMap identification during serialization\n * @category Constants\n */\nexport const ComponentMapKey = \"ComponentMap\"\n\n/**\n * Property key used for ComponentClassesMap identification during serialization\n * @category Constants\n */\nexport const ComponentClassesMapKey = \"ComponentClassesMap\"\n\n/**\n * Variadic type helper that preserves the strongly typed parameter interfaces used by the compiler and intellisense.\n * Works with single returned types or spread array returned types.\n * @category Types\n */\nexport type SingleOrArray<T extends any[]> =\n // return a single variadic item when only 1 item is specified\n T['length'] extends 1 ? T[0]\n // otherwise return an array of variadic types\n : { [Index in keyof T]: T[Index] }\n\n/**\n * Used to return component instance data.\n * \n * Note: This is not used for registering components or extending component classes\n * @category Types\n */\nexport interface Component { }\n\n/**\n * @category Types\n * @example\n * \n * class PositionComponent {\n * constructor(x, y) {\n * this.x = x;\n * this.y = y;\n * }\n * }\n */\nexport type ComponentClass<ComponentInstance> = (new (...args: any[]) => ComponentInstance) & {\n // static property\n hashId?: number;\n};\n\n/**\n* Used for inferring generic type spread for classes\n* @category Types\n*/\nexport type ComponentClasses<T extends Component[]> =\n { [Index in keyof T]: ComponentClass<T[Index]> }\n\n/**\n * Custom iterator interface that includes a reset function\n * @category Types\n */\nexport type Iterator<T> = {\n /**\n * Gets the next result in the iteration\n */\n next: () => IteratorResult<T>\n /**\n * Resets the iterator back to the beginning\n */\n reset: () => void\n /**\n * Returns the iterator instance\n */\n [Symbol.iterator]: () => Iterator<T>\n}\n\n/**\n * Helper type for late-bound iterator assignment with IntelliSense support\n * @category Types\n * @example\n * \n * let someIterator: IComponentIterator<[Player, Position]>\n * \n * // assignment made somewhere else in the code\n * const [player, position] = someIterator(Player, Position) ?? []\n * position?.x = 123 // position will have IntelliSense\n */\nexport type IComponentIterator<T extends Component[]>\n = Iterator<ComponentClasses<[number, ...T]>>", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n/**\n * Generates a 32-bit integer hash from a string\n * @param str - The string to hash\n * @returns A 32-bit integer hash\n */\nexport function hashString(str: string) {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash |= 0; // Convert to 32bit\n }\n return hash;\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport type { ComponentMap } from './component-map.js';\nimport {\n ComponentClassesMapKey,\n type ComponentClass,\n type Iterator,\n} from './types.js';\nimport { hashString } from './utils.js';\n\n/**\n * Component class map for storing registered component maps\n * @category Maps\n */\nexport class ComponentClassesMap {\n\n private hashIdToName: Map<number, string> = new Map<number, string>()\n private hashIdToIndex = new Map<number, number>();\n private indexToHashId: number[] = [];\n private maps: ComponentMap<any>[] = [];\n\n /**\n * Creates a new component classes map\n * @param entries - Optional initial data for the map\n */\n constructor(entries?: readonly (readonly [number, ComponentMap<any>])[] | null) {\n if (entries) {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n this.setByHashId(entry[0], entry[1]);\n }\n }\n }\n\n /**\n * Returns the number of registered component maps\n */\n get size() {\n return this.maps.length;\n }\n\n /**\n * Clears all maps and internal indices while preserving array references\n */\n clear(): void {\n this.maps.length = 0;\n this.indexToHashId.length = 0;\n this.hashIdToIndex.clear();\n }\n\n /**\n * Retrieves a component map using the component class\n * @param componentClass - The component class to get the map for\n * @returns The {@link ComponentMap} for the specified class, or undefined if not found\n */\n get<T>(componentClass: ComponentClass<T>): ComponentMap<T> | undefined {\n const index = this.hashIdToIndex.get(componentClass.hashId!);\n return index !== undefined ? this.maps[index] : undefined;\n }\n\n /**\n * Registers a component map. Automatically generates a hashId from the class name if missing\n * @param componentClass - The component class to register\n * @param map - The {@link ComponentMap} instance to store\n * @returns The {@link ComponentClassesMap} instance for chaining\n */\n set<T>(componentClass: ComponentClass<T>, map: ComponentMap<T>): this {\n if (componentClass.hashId === undefined) {\n componentClass.hashId = hashString(componentClass.name);\n }\n\n this.hashIdToName.set(componentClass.hashId, componentClass.name);\n return this.setByHashId(componentClass.hashId!, map);\n }\n\n /**\n * Maps a specific numeric hash id to a component map instance.\n * @param hash - The numeric hash id\n * @param map - The {@link ComponentMap} instance to store\n * @returns The {@link ComponentClassesMap} instance for chaining\n */\n setByHashId(hash: number, map: ComponentMap<any>): this {\n const existingIndex = this.hashIdToIndex.get(hash);\n\n if (existingIndex !== undefined) {\n this.maps[existingIndex] = map;\n } else {\n this.hashIdToIndex.set(hash, this.maps.length);\n this.indexToHashId.push(hash);\n this.maps.push(map);\n }\n\n return this;\n }\n\n /**\n * Removes a component map and re-orders internal storage to maintain density\n * @param componentClass - The component class to remove the map for\n * @returns True if the map was removed, otherwise false\n */\n delete(componentClass: ComponentClass<any>): boolean {\n const hashId = componentClass.hashId!;\n const index = this.hashIdToIndex.get(hashId);\n if (index === undefined) return false;\n\n const lastIndex = this.maps.length - 1;\n const lastHash = this.indexToHashId[lastIndex];\n\n // Swap\n this.maps[index] = this.maps[lastIndex];\n this.indexToHashId[index] = lastHash;\n\n // Update map pointer\n this.hashIdToIndex.set(lastHash, index);\n\n // Pop\n this.maps.pop();\n this.indexToHashId.pop();\n this.hashIdToIndex.delete(hashId);\n return true;\n }\n\n /**\n * Executes a callback for every map, providing the instance and its registered name\n * @param callback - The callback to execute\n */\n forEach(callback: (value: ComponentMap<any>, name: string) => void) {\n for (let i = 0; i < this.maps.length; i++) {\n callback(this.maps[i], this.hashIdToName.get(this.indexToHashId[i])!);\n }\n }\n\n /**\n * Returns an iterator of all component map instances \n * @returns An {@link ArrayIterator} of {@link ComponentMap} instances\n */\n values(): ArrayIterator<ComponentMap<any>> { return this.maps.values() }\n\n /**\n * Returns an iterator of [hashId, componentMap] pairs\n * @returns An {@link Iterator} instance\n */\n entries(): Iterator<[number, ComponentMap<any>]> {\n let index = 0;\n const instances = this.maps;\n const hashes = this.indexToHashId;\n\n return {\n next(): IteratorResult<[number, ComponentMap<any>]> {\n if (index < instances.length) {\n const value: [number, ComponentMap<any>] = [hashes[index], instances[index]];\n index++;\n return { value, done: false };\n }\n return { value: undefined as any, done: true };\n },\n reset() { index = 0; },\n [Symbol.iterator]() { return this; }\n };\n }\n\n /**\n * Called when using JSON.stringify\n * @returns An object representation for serialization\n */\n toJSON() {\n return { [ComponentClassesMapKey]: 1, iterable: [...this.entries()] };\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport {\n ComponentMapKey,\n type Iterator\n} from './types.js';\n\n/**\n * Component map for storing entity ids and related component data\n * @category Maps\n */\nexport class ComponentMap<TComponentInstance> implements Iterable<[number, TComponentInstance]> {\n\n private indices: number[] = [];\n\n private entities: number[] = [];\n\n private instances: TComponentInstance[] = [];\n\n /**\n * Creates a new component map\n * @param entries - Optional initial data for the map\n */\n constructor(entries?: readonly (readonly [number, TComponentInstance])[] | null) {\n if (entries) {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n this.set(entry[0], entry[1]);\n }\n }\n }\n\n /**\n * Returns the number of entities in the map\n */\n get size() {\n return this.instances.length;\n }\n\n /**\n * Clears all component data from the map\n */\n clear() {\n this.indices = [];\n this.entities.length = 0;\n this.instances.length = 0;\n }\n\n /**\n * Adds or updates component data for an entity\n * @param entityId - The entity id to set\n * @param component - The component data to set\n */\n set(entityId: number, component: TComponentInstance) {\n if (this.has(entityId)) {\n this.instances[this.indices[entityId]] = component;\n return;\n }\n this.indices[entityId] = this.instances.length;\n this.entities.push(entityId);\n this.instances.push(component);\n }\n\n /**\n * Gets the component data for an entity\n * @param entityId - The entity id to get\n * @returns The component data, or undefined if not found\n */\n get(entityId: number) {\n const index = this.indices[entityId];\n return index !== undefined && this.entities[index] === entityId\n ? this.instances[index]\n : undefined;\n }\n\n /**\n * Removes component data for an entity\n * @param entityId - The entity id to remove\n * @returns True if the component was removed, otherwise false\n */\n delete(entityId: number) {\n const index = this.indices[entityId];\n if (index === undefined || index === -1 || this.entities[index] !== entityId) return false;\n\n // swap and pop with last element to keep dense\n const lastIdx = this.instances.length - 1;\n const lastEntity = this.entities[lastIdx];\n this.instances[index] = this.instances[lastIdx];\n this.entities[index] = lastEntity;\n this.indices[lastEntity] = index;\n this.instances.pop();\n this.entities.pop();\n\n // invalidate index\n this.indices[entityId] = -1;\n\n return true;\n }\n\n /**\n * Checks if an entity has a component in this map\n * @param entityId - The entity id to check\n * @returns True if the entity has a component, otherwise false\n */\n has(entityId: number) {\n const index = this.indices[entityId];\n return index !== undefined && index !== -1 && this.entities[index] === entityId;\n }\n\n /**\n * Executes a callback for every map, providing the component data and its entity id\n * @param callback - The callback to execute\n */\n forEach(callback: (value: TComponentInstance, key: number) => void) {\n for (let i = 0; i < this.instances.length; i++) {\n callback(this.instances[i], this.entities[i]);\n }\n }\n\n /**\n * Returns the first entry\n * @returns A tuple of [entityId, componentData], or undefined if empty\n */\n firstEntry(): [entityId: number, value: TComponentInstance] | undefined {\n return this.entities.length === 0\n ? undefined\n : [this.entities[0], this.instances[0]];\n }\n\n /**\n * Returns the first entity id\n * @returns The first entity id, or undefined if empty\n */\n firstKey(): number | undefined {\n return this.entities.length === 0\n ? undefined\n : this.entities[0];\n }\n\n /**\n * Returns the first entity data\n * @returns The first component data, or undefined if empty\n */\n firstValue(): TComponentInstance | undefined {\n return this.instances.length === 0\n ? undefined\n : this.instances[0];\n }\n\n /**\n * Returns an iterator of [entityId, componentData] pairs\n * @returns An {@link Iterator} instance\n */\n [Symbol.iterator](): Iterator<[number, TComponentInstance]> {\n return this.entries();\n }\n\n /**\n * Returns an iterator of all entity ids\n * @returns An {@link ArrayIterator} of entity ids\n */\n keys(): ArrayIterator<number> {\n return this.entities.values();\n }\n\n /**\n * Returns an iterator of all component data\n * @returns An {@link ArrayIterator} of component data\n */\n values(): ArrayIterator<TComponentInstance> {\n return this.instances.values();\n }\n\n /**\n * Returns an iterator of [entityId, componentData] pairs\n * @returns An {@link Iterator} instance\n */\n entries(): Iterator<[number, TComponentInstance]> {\n let index = 0;\n const entities = this.entities;\n const instances = this.instances;\n\n return {\n next(): IteratorResult<[number, TComponentInstance]> {\n if (index < instances.length) {\n const result: IteratorResult<[number, TComponentInstance]> = {\n value: [entities[index], instances[index]],\n done: false\n };\n index++;\n return result;\n }\n return { value: <any>undefined, done: true };\n },\n reset() {\n index = 0;\n },\n [Symbol.iterator]() {\n return this;\n },\n };\n }\n\n /**\n * Called when using JSON.stringify\n * @returns An object representation for serialization\n */\n toJSON() {\n return { [ComponentMapKey]: 1, iterable: [...this.entries()] };\n }\n\n /**\n * Returns an array of objects for tabular display\n * @returns An array of objects formatted for {@link console.table}\n */\n toTable(): any[] {\n const table = []\n for (const [key, value] of this.entries()) {\n const entity = value as { new(): TComponentInstance };\n const meta: Record<string, any> = {};\n meta[\"entity.key\"] = key;\n meta[\"entity.type\"] = entity.constructor.name;\n table.push({ ...meta, ...entity });\n }\n return table;\n }\n\n /**\n * Prints entity data in a tabular format to the console\n * @param properties - Optional filter. Specifies which property columns to display in the tables.\n * @returns The {@link ComponentMap} instance for chaining\n */\n printTable(properties: string[] = []): this {\n console.table(this.toTable(), properties);\n return this;\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n/**\n * Thrown when trying to register a component that is missing a 'name' parameter\n * @category Errors\n */\nexport class ComponentTypeKeyMissing extends Error {\n constructor() {\n super(`Component type is missing the 'name' parameter. i.e. a constructor name`);\n }\n}\n\n/**\n * Thrown when trying to access a component that has not been registered\n * @param componentName - The name of the unregistered component\n * @category Errors\n */\nexport class ComponentNotRegistered extends Error {\n constructor(public componentName: string) {\n super(`Component map does not exist for '${componentName}'`);\n }\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport type { ComponentMap } from './component-map.js';\nimport type { ComponentQuery } from './query.js';\n\n/**\n * An iterator for yielding entity ids and their associated component data\n * @category Iterators\n * @example\n * // construct an instance\n * const iterator = new ComponentIterator(new ComponentQuery(entityMap, Player, Position))\n * \n * // iterate component data that is related to the Player\n * for(const [entityId, player, position] of iterator) { }\n * \n * // you can also reset the iterator back to the start\n * // without having to create a new ComponentIterator instance\n * iterator.reset()\n * for(const [entityId, player, position] of iterator) { }\n */\nexport class ComponentIterator<TKey, TRelated extends any[]> {\n private keyMap: ComponentMap<TKey>;\n private componentMaps: ComponentMap<any>[] = [];\n // iteration state\n private entries: Iterator<[number, TKey]>;\n\n /**\n * Creates a new component iterator\n * @param query - The {@link ComponentQuery} to iterate over\n */\n constructor(query: ComponentQuery<TKey, TRelated>) {\n // @ts-ignore internal private var accessor\n this.keyMap = query.keyMap\n // @ts-ignore internal private var accessor\n this.componentMaps = query.componentMaps\n this.entries = this.keyMap.entries();\n }\n\n /**\n * Gets the next iterator value\n * @returns An {@link IteratorResult} containing the next [entityId, keyComponentData, ...relatedComponentData] tuple\n */\n next(): IteratorResult<[number, TKey, ...TRelated]> {\n const entry = this.entries.next();\n const { value, done } = entry;\n if (done) return { value, done };\n\n const entityId = value[0];\n\n // append the related components\n for (let i = 0; i < this.componentMaps.length; i++) {\n const map = this.componentMaps[i];\n value.push(map.get(entityId));\n }\n\n return { value: value as any, done: false };\n }\n\n /**\n * Resets the iterator back to the first entry\n */\n reset() {\n this.entries = this.keyMap.entries();\n }\n\n /**\n * Returns this iterator instance\n */\n [Symbol.iterator]() { return this; }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport type { ComponentMap } from './component-map.js';\nimport type { EntityMap } from './entity-map.js';\nimport { ComponentIterator } from './iterator.js';\nimport type { ComponentClass, ComponentClasses, Iterator, SingleOrArray } from './types.js';\n\n/**\n * A reusable query for retrieving entities and their components\n * @category Queries\n * @example\n * const query = ecs.query(Player, Position)\n * \n * // get the first entry\n * const [playerId, player, position] = query.firstEntry() ?? []\n * \n * // get the first key\n * const [playerId, position] = query.firstKey() ?? []\n * \n * // get the first value\n * const [player, position] = query.firstValue() ?? []\n * \n * // iterate\n * for (const [playerId, player, position] of query) {\n * \n * }\n */\nexport class ComponentQuery<TKey, TRelated extends any[]> {\n private keyMap: ComponentMap<TKey>\n private componentMaps: ComponentMap<any>[] = []\n\n /**\n * Creates a new component query\n * @param ecs - The {@link EntityMap} instance to query\n * @param components - The first component class <TKey> is the primary component. Optional additional component classes <TRelated> to retrieve for each entity.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n */\n constructor(\n public ecs: EntityMap,\n ...components: [ComponentClass<TKey>, ...ComponentClasses<TRelated>]\n ) {\n this.keyMap = this.ecs.getMap(components[0])!;\n for (let i = 1; i < components.length; i++) {\n this.componentMaps.push(this.ecs.getMap(components[i])!)\n }\n }\n\n /**\n * Gets the first entry matching the query.\n * \n * Includes the entity id, the key component data, and any related component data.\n * @returns A tuple of `[entityId, keyComponentData, ...relatedComponentData]`, or `undefined` if no entities match.\n */\n firstEntry(): [number, TKey, ...TRelated] | undefined;\n firstEntry() {\n if (this.componentMaps.length === 0) return this.keyMap.firstEntry()\n\n const [entityId, entryValue] = this.keyMap.firstEntry() ?? []\n if (entityId === undefined) return undefined;\n\n const results: any[] = [entityId, entryValue]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Gets the first key matching the query.\n * \n * @returns The entity id if no related components were specified in the constructor.\n * \n * Otherwise, a tuple of `[entityId, ...relatedComponentData]`.\n * \n * Returns `undefined` if no entities match.\n */\n firstKey(): SingleOrArray<[number, ...TRelated]> | undefined;\n firstKey() {\n const entityId = this.keyMap.firstKey()\n if (this.componentMaps.length === 0) return entityId;\n if (entityId === undefined) return undefined;\n\n const results: any[] = [entityId]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Get the first component data matching the query.\n * \n * @returns The key component data if no related components were specified in the constructor.\n * \n * Otherwise, a tuple of `[keyComponentData, ...relatedComponentData]`.\n * \n * Returns `undefined` if no entities match.\n */\n firstValue(): SingleOrArray<[TKey, ...TRelated]> | undefined;\n firstValue() {\n if (this.componentMaps.length === 0) return this.keyMap.firstValue()\n\n const [entityId, keyValue] = this.keyMap.firstEntry() ?? []\n if (entityId === undefined) return undefined;\n\n const results = [keyValue]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Returns the count of entities matching the query\n */\n get entityCount() {\n return this.keyMap.size\n }\n\n /**\n * Destroys all entities matching the query\n * @returns The total number of components destroyed across all affected entities\n * @example\n * const destroyedCount = query.destroyEntities()\n */\n destroyEntities(): number {\n return this.ecs.destroyEntity(...this.keyMap.keys())\n }\n\n /**\n * Gets all entity ids matching the query.\n * \n * @returns An {@link ArrayIterator} of entity ids.\n */\n keys(): ArrayIterator<number> { return this.keyMap.keys() }\n\n /**\n * Gets all component data matching the query.\n *\n * @returns An {@link Iterator} of `[keyComponentData, ...relatedComponentData]` tuples containing component data\n */\n values(): Iterator<[TKey, ...TRelated]> {\n const keyMap = this.keyMap;\n const componentMaps = this.componentMaps;\n let keysIterator = keyMap.keys();\n\n return {\n next(): IteratorResult<[TKey, ...TRelated]> {\n const key = keysIterator.next();\n if (key.done) return { value: <any>undefined, done: true };\n\n const entityId = key.value;\n const keyComponent = keyMap.get(entityId);\n\n // append the related components\n const value = [keyComponent];\n for (let i = 0; i < componentMaps.length; i++) {\n const map = componentMaps[i];\n value.push(map.get(entityId));\n }\n\n return { value: value as any, done: false };\n },\n reset() { keysIterator = keyMap.keys(); },\n [Symbol.iterator]() { return this; },\n };\n }\n\n /**\n * Gets all component data entries matching the query\n * \n * @returns A {@link ComponentIterator} instance that yields `[entityId, keyComponentData, ...relatedComponentData]`\n */\n entries() { return this[Symbol.iterator](); }\n\n /**\n * @returns A {@link ComponentIterator} instance that yields `[entityId, keyComponentData, ...relatedComponentData]`\n */\n [Symbol.iterator]() {\n return new ComponentIterator(this);\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { ComponentClassesMap } from './component-classes.js';\nimport { ComponentMap } from './component-map.js';\nimport { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js';\nimport { ComponentIterator } from './iterator.js';\nimport { ComponentQuery } from './query.js';\nimport {\n ComponentClassesMapKey,\n ComponentMapKey,\n type Component,\n type ComponentClass,\n type ComponentClasses,\n type SingleOrArray\n} from './types.js';\n\n/**\n * Class for storing entities and their relationships\n * @category Maps\n */\nexport class EntityMap {\n /**\n * Registered component classes that contain the component data\n */\n public components = new ComponentClassesMap()\n\n private nextId: number = 0\n\n /**\n * Registers component classes with the {@link EntityMap}\n * @param componentClasses - One or more component classes to register\n * @returns The {@link EntityMap} instance for chaining\n * @throws {@link ComponentTypeKeyMissing} when the specified component type is missing a 'name' parameter\n * @example\n * // component class\n * class MyComponent {\n * constructor(x) {\n * this.x = x;\n * }\n * }\n *\n * ecs.register(MyComponent);\n * // or multiple\n * ecs.register(MyComponent1, MyComponent2);\n */\n register<TComponentClasses extends ComponentClass<any>[]>(...componentClasses: TComponentClasses) {\n for (const componentClass of componentClasses) {\n const componentName = componentClass.name;\n if (componentName === undefined) throw new ComponentTypeKeyMissing();\n\n // create the component map\n // const componentDataMap: ComponentMap<any> = new ComponentMap();\n this.components.set(componentClass, new ComponentMap());\n }\n\n // chain\n return this;\n }\n\n /**\n * Gets a component class map\n * @param component - The component class to get the map for\n * @returns The {@link ComponentMap} for the specified component, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * const positionMap = ecs.getMap(Position)\n * for(const [entityId, position] of positionMap) {\n * position.x += 1\n * }\n */\n getMap<T>(component: ComponentClass<T>): ComponentMap<T> | undefined {\n const map = this.components.get(component);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n return map\n }\n\n /**\n * @deprecated Use {@link EntityMap.firstEntity} instead\n * \n * Returns an array of component data for the first entity associated with the keyComponent\n * @param keyComponent - The component class used to find the first entity\n * @returns An array of components for the first entity, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // get the first entity\n * const playerEntity = ecs.first(Player) ?? []\n */\n first(keyComponent: ComponentClass<any>): Component[] | undefined { return this.firstEntity(keyComponent); }\n\n /**\n * Returns an array of component data for the first entity associated with the keyComponent\n * @param keyComponent - The component class used to find the first entity\n * @returns An array of components for the first entity, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // get the first entity\n * const playerEntity = ecs.firstEntity(Player) ?? []\n */\n firstEntity(keyComponent: ComponentClass<any>): Component[] | undefined {\n const entityId = this.getMap(keyComponent)?.firstKey();\n if (entityId === undefined) return undefined;\n\n return this.get(entityId);\n }\n\n /**\n * Returns an array of component data arrays associated with the keyComponent\n * @param keyComponent - The component class used to find the entities\n * @returns An array of component arrays, or undefined if the key component map is not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // get an array of component arrays: e.g. [[Player, Position, Velocity], [Player, Position, Velocity], ...]\n * const entities = ecs.entityValues(Player) ?? []\n */\n entityValues(keyComponent: ComponentClass<any>): Array<Component[]> | undefined {\n const entities = this.getMap(keyComponent)?.keys();\n if (entities === undefined) return undefined;\n\n return [...entities].map(x => this.get(x)!)\n }\n\n /**\n * Gets the first entity entry for a component class\n * @param keyComponent - The component class to find the first entry for\n * @param components - Additional component classes to retrieve for the same entity\n * @returns A tuple containing the entity id followed by the component data, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // return the first entry\n * const [entityId, player] = ecs.firstEntry(Player) ?? []\n * \n * // or return multiple related components in addition to the first entry\n * const [entityId, player, position, direction] = ecs.firstEntry(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstEntry<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ): [number, TKey, ...TRelated] | undefined;\n firstEntry(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n if (components.length === 0) return this.getMap(keyComponent)?.firstEntry()\n\n return this.firstKey(keyComponent, keyComponent, ...components);\n }\n\n /**\n * Gets the first entity id for a component class \n * and optionally any related component data\n * @param keyComponent - The component class used to find the first entity\n * @param components - Additional component classes to retrieve for the same entity\n * @returns If only keyComponent is provided, returns the entity id. \n * \n * If related components are provided, returns a tuple with the id and component data. \n * \n * Returns undefined if not found.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first entity id\n * const entityId = ecs.firstKey(Player)\n * \n * // or return multiple related component in addition to entity id\n * const [entityId, position, direction] = ecs.firstKey(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstKey<TKey, TRelated extends any[]>(\n keyComponent: TKey,\n ...components: ComponentClasses<TRelated>\n ): SingleOrArray<[number, ...TRelated]> | undefined;\n firstKey(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n const entityId = this.getMap(keyComponent)?.firstKey();\n\n // single component key\n if (arguments.length === 1) return entityId;\n if (entityId === undefined) return undefined;\n\n // attach related component data\n return [entityId, ...components.map(x => this.getEntity(entityId, x))];\n }\n\n /**\n * Gets the first entity component data for a component class\n * and optionally any related component data\n * @param keyComponent - The component class used to find the first entity\n * @param components - Additional component classes to retrieve for the same entity\n * @returns If only keyComponent is provided, returns the component data. \n * \n * If related components are provided, returns a tuple with all component data. \n * \n * Returns undefined if not found.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first component data\n * const player = ecs.firstValue(Player)\n * \n * // or multiple related data in addition to the first component\n * const [player, position, direction] = ecs.firstValue(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstValue<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ): SingleOrArray<[TKey, ...TRelated]> | undefined;\n firstValue(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n // single component\n if (arguments.length === 1) return this.getMap(keyComponent)?.firstValue();\n\n // get the first entry\n const [entityId, keyValue] = this.getMap(keyComponent)?.firstEntry() ?? [];\n if (entityId === undefined) return undefined;\n\n // attach related components\n return [keyValue, ...components.map(x => this.getEntity(entityId, x))]\n }\n\n /**\n * Internal helper to get component data for an entity\n * @param entityId - The entity id to get the component for\n * @param component - The component class to get the data of\n * @returns The component data if it exists, otherwise undefined\n * @throws {@link ComponentNotRegistered} when the specified component is not registered \n */\n private getEntity<T>(entityId: number, component: ComponentClass<T>): T | undefined {\n const map = this.components.get(component);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n\n return map.get(entityId);\n }\n\n /**\n * Gets component data related to an entity id\n * @param entityId - The entity id to get component(s) for\n * @param components - One or more component classes to retrieve. If none provided, retrieves all components for the entity.\n * @returns Depending on parameters: a single component, an array of specified components, or an array of all components for the entity.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // get one by id\n * const player = ecs.get(entityId, Player)\n * \n * // get multiple by id\n * const [player, position] = ecs.get(entityId, Player, Position) ?? []\n * \n * // get all by id\n * const playerEntity = ecs.get(entityId) ?? []\n */\n get(entityId: number): Component[] | undefined;\n get<T>(entityId: number, component: ComponentClass<T>): T | undefined;\n get<T extends any[]>(entityId: number, ...components: ComponentClasses<T>): SingleOrArray<T> | undefined;\n get(entityId: number, ...components: ComponentClasses<any>): Component | Component[] | undefined {\n // return a single component\n if (components.length === 1) return this.getEntity(entityId, components[0]);\n // return filtered components\n if (components.length > 1) return components.map(x => this.getEntity(entityId, x));\n // return all components\n return [...this.components.values()]\n .filter(v => v.has(entityId))\n .map(v => v.get(entityId));\n }\n\n /**\n * Check if a component exists for an entity\n * @param entityId - The entity id to check for the component\n * @param component - The component class to check\n * @returns True if the entity has the component, otherwise false\n * @example\n * const exists = ecs.has(entityId, Position)\n */\n has<T>(entityId: number, component: ComponentClass<T>): boolean {\n // get the component map\n const map = this.components.get(component);\n if (map === undefined) return false\n\n return map.has(entityId);\n }\n\n /**\n * Checks if all of the specified components exist for an entity\n * @param entityId - The entity id to check\n * @param components - One or more component classes to check for\n * @returns True if the entity has ALL specified components, otherwise false\n * @example\n * const hasAll = ecs.hasAll(entityId, Position, Velocity)\n */\n hasAll<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component);\n if (map === undefined) return false;\n if (map.has(entityId) === false) return false;\n }\n return true\n }\n\n /**\n * Checks if any of the specified components exist for an entity\n * @param entityId - The entity id to check\n * @param components - One or more component classes to check for\n * @returns True if the entity has ANY of the specified components, otherwise false\n * @example\n * const hasAny = ecs.hasAny(entityId, Position, Velocity)\n */\n hasAny<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component);\n if (map === undefined) continue;\n if (map.has(entityId)) return true;\n }\n return false\n }\n\n /**\n * Internal helper to set component data for an entity\n * @param entityId - The entity id to set the component for\n * @param componentData - The component data to set\n * @returns The component data that was set\n * @throws {@link ComponentNotRegistered} when the component class of the instance is not registered\n */\n private setEntity<T extends Component>(entityId: number, componentData: T): T {\n // get the component map\n const map = this.components.get((<ComponentClass<any>>componentData.constructor));\n if (map === undefined) throw new ComponentNotRegistered(componentData.constructor.name)\n\n // set the entity on the entity map\n map.set(entityId, componentData);\n\n // return instance\n return componentData;\n }\n\n /**\n * Add or update multiple component data for an entity\n * @param entityId - The entity id to set components for\n * @param component - A single component data instance to set\n * @param components - Multiple component data instances to set\n * @returns The single component data or an array of component data that were set\n * @throws {@link ComponentNotRegistered} when any of the component classes are not registered\n * @example\n * // set one\n * const player = ecs.set(entityId, new Player());\n * \n * // or set multiple\n * const [player, position] = ecs.set(\n * entityId,\n * new Player(),\n * new Position()\n * );\n */\n set<T extends Component>(entityId: number, component: T): T;\n set<T extends Component[]>(entityId: number, ...components: T): T;\n set(entityId: number, ...components: Component[]): Component | Component[] {\n if (components.length > 1) return components.map(x => this.setEntity(entityId, x))\n\n // set and return a single component\n return this.setEntity(entityId, components[0])\n }\n\n /**\n * Removes the specified component(s) from an entity\n * @param entityId - The entity id to remove components from\n * @param components - One or more component classes to remove\n * @example\n * ecs.remove(entityId, Position);\n */\n remove<T extends ComponentClass<any>[]>(entityId: number, ...components: T) {\n for (const component of components) {\n this.removeByKey(entityId, component)\n }\n }\n\n /**\n * Removes the specified component from an entity\n * @param entityId - The entity id to remove the component from\n * @param component - The component class to remove\n * @returns True if the component was successfully removed, otherwise false\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * ecs.removeByKey(entityId, Position);\n */\n removeByKey(entityId: number, component: ComponentClass<any>) {\n // get the entity map\n const entityMap = this.components.get(component);\n\n // ensure the map is defined\n if (entityMap === undefined) throw new ComponentNotRegistered(component.name);\n\n // get the entity\n const entity = entityMap.get(entityId);\n if (entity === undefined) return false;\n\n // remove the entity from the entity map\n return entityMap.delete(entityId);\n }\n\n /**\n * Deletes all components from an entity\n * @param entityIds - One or more entity ids to destroy\n * @returns The total number of components destroyed\n * @example\n * const destroyedCount = ecs.destroyEntity(entityId1)\n * \n * // or multiple\n * const destroyedCount = ecs.destroyEntity(entityId1, entityId2)\n */\n destroyEntity(...entityIds: number[]): number {\n let deletedCount = 0;\n for (let index = 0; index < entityIds.length; index++) {\n const entityId = entityIds[index];\n for (const map of this.components.values()) {\n if (map.has(entityId)) {\n map.delete(entityId);\n deletedCount++;\n }\n }\n }\n return deletedCount;\n }\n\n // TODO create id generator\n /**\n * Creates a new entity id for the EntityMap\n * @returns A new unique entity id\n * @example\n * const newEntityId = ecs.getNextId()\n * ecs.set(newEntityId, new Player())\n */\n getNextId(): number {\n this.nextId++;\n return this.nextId;\n }\n\n /**\n * Clears all registered component classes and all entity data\n * @returns The {@link EntityMap} instance for chaining\n */\n clear() {\n this.components.clear();\n this.nextId = 0\n return this;\n }\n\n /**\n * Clears all component data while keeping the registered component classes\n * @returns The {@link EntityMap} instance for chaining\n */\n clearComponents() {\n this.components.forEach(x => x.clear())\n this.nextId = 0\n return this;\n }\n\n /**\n * Iterates over each entity that contains the specified key component\n * @param keyComponent - The primary component class used to filter entities\n * @param components - Additional component classes to retrieve for each entity\n * @returns A {@link ComponentIterator} that yields tuples of [entityId, keyComponentData, ...relatedComponentData]\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // iterate each component data that is related to the Player entity\n * const iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) { }\n * \n * // you can also declare the type of iterator before it's assigned\n * // using the ComponentIterator type\n * let iterator: ComponentIterator<[Player, Position]>\n * \n * // then with late bound assignment (keeping the iterator intellisense)\n * iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) {\n * const moving = player.isMoving\n * }\n */\n iterator<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ) {\n return new ComponentIterator(new ComponentQuery(this, keyComponent, ...components));\n }\n\n /**\n * Creates a query that can be stored and reused\n * @param keyComponent - The primary component class used to filter entities\n * @param components - Additional component classes to retrieve for each entity\n * @returns A {@link ComponentQuery} instance\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * const query = ecs.query(Player, Position)\n * \n * // get the first entry\n * const [playerId, player, position] = query.firstEntry() ?? []\n * \n * // get the first key\n * const [playerId, position] = query.firstKey() ?? []\n * \n * // get the first value\n * const [player, position] = query.firstValue() ?? []\n * \n * // iterate\n * for (const [playerId, player, position] of query) {\n * \n * }\n */\n query<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ) {\n return new ComponentQuery(this, keyComponent, ...components)\n }\n\n /**\n * Prints all component maps in a tabular format to the console.\n * \n * Additional generated columns are:\n * \n * 'Entity.Key' is the entity id\n * \n * 'Entity.Type' is the component name\n * \n * @param components - Optional filter. Only includes specific component class names.\n * @param properties - Optional filter. Specifies which property columns to display in the tables.\n * @returns The {@link EntityMap} instance for chaining\n */\n printTable(components?: string[]): this;\n printTable(components?: string[], properties?: string[]): this;\n printTable(components: string[] = [], properties: string[] = []) {\n this.components.forEach((map, key) => {\n if (components.length === 0 || components.includes(key)) {\n console.table(map.toTable(), properties);\n }\n });\n return this;\n }\n\n /**\n * Prints all component data for the specified entity id in a tabular format to the console\n * \n * Additional generated columns are:\n * \n * 'Entity.Type' is the component name\n * \n * @param entityId - The entity id to print\n * @param properties - Optional filter. Specifies which property columns to display in the tables.\n * @returns The {@link EntityMap} instance for chaining\n */\n printEntity(entityId: number, properties: string[] = []) {\n for (const map of this.components.values()) {\n if (map.has(entityId) === false) continue;\n\n const data = map.get(entityId);\n const columns = {\n 'entity.type': data.constructor.name,\n ...data\n };\n console.table({ [entityId]: columns }, properties);\n }\n\n return this;\n }\n\n /**\n * Parses the JSON and returns an {@link EntityMap} object\n * @param json - The JSON string representing an {@link EntityMap}\n * @returns A restored {@link EntityMap} instance\n * @example\n * const json = JSON.stringify(ecs);\n * const restoredMap = EntityMap.parse(json);\n */\n static parse(json: string): EntityMap {\n const restored = JSON.parse(json, function (key: string, value: any) {\n if (value.hasOwnProperty('components')) {\n Reflect.setPrototypeOf(value, EntityMap.prototype);\n return value;\n }\n if (value.hasOwnProperty(ComponentMapKey)) return new ComponentMap(value.iterable);\n if (value.hasOwnProperty(ComponentClassesMapKey)) return new ComponentClassesMap(value.iterable);\n return this[key];\n });\n return restored;\n }\n\n /**\n * A tracing method used for debugging.\n * Intercepts all functions specified and logs each call to the console.\n * @param funcFilter - A list of function names you want to intercept. If no function names are specified then will log all functions called.\n * @returns A new proxy of an {@link EntityMap} with tracing enabled\n */\n static createWithTracing(funcFilter: string[] = []) {\n const traceHandler = {\n get(target: any, propKey: string) {\n const targetValue = target[propKey]\n\n if (typeof targetValue === 'function' && (funcFilter.length === 0 || funcFilter.includes(propKey))) {\n return function (this: any, ...args: any[]) {\n console.groupCollapsed('ecs trace', propKey, args);\n console.trace();\n console.groupEnd();\n return targetValue.apply(this, args);\n }\n }\n\n return targetValue;\n }\n }\n\n return new Proxy(new EntityMap(), traceHandler)\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * An entity component system library for JavaScript\n * @showCategories\n * @module ecsjs\n */\nimport { EntityMap } from './entity-map.js'\nexport { ComponentClassesMap } from './component-classes.js'\nexport { ComponentMap } from './component-map.js'\nexport { EntityMap } from './entity-map.js'\nexport type { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js'\nexport { ComponentIterator } from './iterator.js'\nexport { ComponentQuery } from './query.js'\nexport type { ComponentClass, IComponentIterator } from './types.js'\n\n/**\n * A global default instance of an {@link EntityMap}\n * \n * Provides a convenient way to use the ECS without managing multiple maps.\n * \n * See the [cheat sheet](https://gitlab.com/ecsjs/ecs/-/blob/master/docs/cheat-sheet.md) for more examples.\n * @category Constants\n * @example\n * // register component(s)\n * ecs.register(Player, Position)\n * \n * // create an entity and set its components\n * const [player, position] = ecs.set(ecs.getNextId(), new Player(), new Position(10, 40))\n */\nexport const ecs = new EntityMap()\n\nif (typeof window !== 'undefined') {\n // @ts-ignore: exports to window\n window.ecs = ecs\n} else if (typeof module !== 'undefined' && module !== null) {\n // exports to nodejs\n module.exports = { ecs };\n}"],
5
- "mappings": "AAqBO,IAAMA,EAAkB,eAMlBC,EAAyB,sBCL/B,SAASC,EAAWC,EAAa,CACtC,IAAIC,EAAO,EACX,QAASC,EAAI,EAAGA,EAAIF,EAAI,OAAQE,IAAK,CACnC,IAAMC,EAAOH,EAAI,WAAWE,CAAC,EAC7BD,GAASA,GAAQ,GAAKA,EAAQE,EAC9BF,GAAQ,CACV,CACA,OAAOA,CACT,CCDO,IAAMG,EAAN,KAA0B,CAEvB,aAAoC,IAAI,IACxC,cAAgB,IAAI,IACpB,cAA0B,CAAC,EAC3B,KAA4B,CAAC,EAMrC,YAAYC,EAAoE,CAC9E,GAAIA,EACF,QAASC,EAAI,EAAGA,EAAID,EAAQ,OAAQC,IAAK,CACvC,IAAMC,EAAQF,EAAQC,CAAC,EACvB,KAAK,YAAYC,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CACrC,CAEJ,CAKA,IAAI,MAAO,CACT,OAAO,KAAK,KAAK,MACnB,CAKA,OAAc,CACZ,KAAK,KAAK,OAAS,EACnB,KAAK,cAAc,OAAS,EAC5B,KAAK,cAAc,MAAM,CAC3B,CAOA,IAAOC,EAAgE,CACrE,IAAMC,EAAQ,KAAK,cAAc,IAAID,EAAe,MAAO,EAC3D,OAAOC,IAAU,OAAY,KAAK,KAAKA,CAAK,EAAI,MAClD,CAQA,IAAOD,EAAmCE,EAA4B,CACpE,OAAIF,EAAe,SAAW,SAC5BA,EAAe,OAASG,EAAWH,EAAe,IAAI,GAGxD,KAAK,aAAa,IAAIA,EAAe,OAAQA,EAAe,IAAI,EACzD,KAAK,YAAYA,EAAe,OAASE,CAAG,CACrD,CAQA,YAAYE,EAAcF,EAA8B,CACtD,IAAMG,EAAgB,KAAK,cAAc,IAAID,CAAI,EAEjD,OAAIC,IAAkB,OACpB,KAAK,KAAKA,CAAa,EAAIH,GAE3B,KAAK,cAAc,IAAIE,EAAM,KAAK,KAAK,MAAM,EAC7C,KAAK,cAAc,KAAKA,CAAI,EAC5B,KAAK,KAAK,KAAKF,CAAG,GAGb,IACT,CAOA,OAAOF,EAA8C,CACnD,IAAMM,EAASN,EAAe,OACxBC,EAAQ,KAAK,cAAc,IAAIK,CAAM,EAC3C,GAAIL,IAAU,OAAW,MAAO,GAEhC,IAAMM,EAAY,KAAK,KAAK,OAAS,EAC/BC,EAAW,KAAK,cAAcD,CAAS,EAG7C,YAAK,KAAKN,CAAK,EAAI,KAAK,KAAKM,CAAS,EACtC,KAAK,cAAcN,CAAK,EAAIO,EAG5B,KAAK,cAAc,IAAIA,EAAUP,CAAK,EAGtC,KAAK,KAAK,IAAI,EACd,KAAK,cAAc,IAAI,EACvB,KAAK,cAAc,OAAOK,CAAM,EACzB,EACT,CAMA,QAAQG,EAA4D,CAClE,QAASX,EAAI,EAAGA,EAAI,KAAK,KAAK,OAAQA,IACpCW,EAAS,KAAK,KAAKX,CAAC,EAAG,KAAK,aAAa,IAAI,KAAK,cAAcA,CAAC,CAAC,CAAE,CAExE,CAMA,QAA2C,CAAE,OAAO,KAAK,KAAK,OAAO,CAAE,CAMvE,SAAiD,CAC/C,IAAIG,EAAQ,EACNS,EAAY,KAAK,KACjBC,EAAS,KAAK,cAEpB,MAAO,CACL,MAAoD,CAClD,GAAIV,EAAQS,EAAU,OAAQ,CAC5B,IAAME,EAAqC,CAACD,EAAOV,CAAK,EAAGS,EAAUT,CAAK,CAAC,EAC3E,OAAAA,IACO,CAAE,MAAAW,EAAO,KAAM,EAAM,CAC9B,CACA,MAAO,CAAE,MAAO,OAAkB,KAAM,EAAK,CAC/C,EACA,OAAQ,CAAEX,EAAQ,CAAG,EACrB,CAAC,OAAO,QAAQ,GAAI,CAAE,OAAO,IAAM,CACrC,CACF,CAMA,QAAS,CACP,MAAO,CAAE,CAACY,CAAsB,EAAG,EAAG,SAAU,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAE,CACtE,CAEF,EC9JO,IAAMC,EAAN,KAAyF,CAEtF,QAAoB,CAAC,EAErB,SAAqB,CAAC,EAEtB,UAAkC,CAAC,EAM3C,YAAYC,EAAqE,CAC/E,GAAIA,EACF,QAASC,EAAI,EAAGA,EAAID,EAAQ,OAAQC,IAAK,CACvC,IAAMC,EAAQF,EAAQC,CAAC,EACvB,KAAK,IAAIC,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAC7B,CAEJ,CAKA,IAAI,MAAO,CACT,OAAO,KAAK,UAAU,MACxB,CAKA,OAAQ,CACN,KAAK,QAAU,CAAC,EAChB,KAAK,SAAS,OAAS,EACvB,KAAK,UAAU,OAAS,CAC1B,CAOA,IAAIC,EAAkBC,EAA+B,CACnD,GAAI,KAAK,IAAID,CAAQ,EAAG,CACtB,KAAK,UAAU,KAAK,QAAQA,CAAQ,CAAC,EAAIC,EACzC,MACF,CACA,KAAK,QAAQD,CAAQ,EAAI,KAAK,UAAU,OACxC,KAAK,SAAS,KAAKA,CAAQ,EAC3B,KAAK,UAAU,KAAKC,CAAS,CAC/B,CAOA,IAAID,EAAkB,CACpB,IAAME,EAAQ,KAAK,QAAQF,CAAQ,EACnC,OAAOE,IAAU,QAAa,KAAK,SAASA,CAAK,IAAMF,EACnD,KAAK,UAAUE,CAAK,EACpB,MACN,CAOA,OAAOF,EAAkB,CACvB,IAAME,EAAQ,KAAK,QAAQF,CAAQ,EACnC,GAAIE,IAAU,QAAaA,IAAU,IAAM,KAAK,SAASA,CAAK,IAAMF,EAAU,MAAO,GAGrF,IAAMG,EAAU,KAAK,UAAU,OAAS,EAClCC,EAAa,KAAK,SAASD,CAAO,EACxC,YAAK,UAAUD,CAAK,EAAI,KAAK,UAAUC,CAAO,EAC9C,KAAK,SAASD,CAAK,EAAIE,EACvB,KAAK,QAAQA,CAAU,EAAIF,EAC3B,KAAK,UAAU,IAAI,EACnB,KAAK,SAAS,IAAI,EAGlB,KAAK,QAAQF,CAAQ,EAAI,GAElB,EACT,CAOA,IAAIA,EAAkB,CACpB,IAAME,EAAQ,KAAK,QAAQF,CAAQ,EACnC,OAAOE,IAAU,QAAaA,IAAU,IAAM,KAAK,SAASA,CAAK,IAAMF,CACzE,CAMA,QAAQK,EAA4D,CAClE,QAASP,EAAI,EAAGA,EAAI,KAAK,UAAU,OAAQA,IACzCO,EAAS,KAAK,UAAUP,CAAC,EAAG,KAAK,SAASA,CAAC,CAAC,CAEhD,CAMA,YAAwE,CACtE,OAAO,KAAK,SAAS,SAAW,EAC5B,OACA,CAAC,KAAK,SAAS,CAAC,EAAG,KAAK,UAAU,CAAC,CAAC,CAC1C,CAMA,UAA+B,CAC7B,OAAO,KAAK,SAAS,SAAW,EAC5B,OACA,KAAK,SAAS,CAAC,CACrB,CAMA,YAA6C,CAC3C,OAAO,KAAK,UAAU,SAAW,EAC7B,OACA,KAAK,UAAU,CAAC,CACtB,CAMA,CAAC,OAAO,QAAQ,GAA4C,CAC1D,OAAO,KAAK,QAAQ,CACtB,CAMA,MAA8B,CAC5B,OAAO,KAAK,SAAS,OAAO,CAC9B,CAMA,QAA4C,CAC1C,OAAO,KAAK,UAAU,OAAO,CAC/B,CAMA,SAAkD,CAChD,IAAII,EAAQ,EACNI,EAAW,KAAK,SAChBC,EAAY,KAAK,UAEvB,MAAO,CACL,MAAqD,CACnD,GAAIL,EAAQK,EAAU,OAAQ,CAC5B,IAAMC,EAAuD,CAC3D,MAAO,CAACF,EAASJ,CAAK,EAAGK,EAAUL,CAAK,CAAC,EACzC,KAAM,EACR,EACA,OAAAA,IACOM,CACT,CACA,MAAO,CAAE,MAAY,OAAW,KAAM,EAAK,CAC7C,EACA,OAAQ,CACNN,EAAQ,CACV,EACA,CAAC,OAAO,QAAQ,GAAI,CAClB,OAAO,IACT,CACF,CACF,CAMA,QAAS,CACP,MAAO,CAAE,CAACO,CAAe,EAAG,EAAG,SAAU,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAE,CAC/D,CAMA,SAAiB,CACf,IAAMC,EAAQ,CAAC,EACf,OAAW,CAACC,EAAKC,CAAK,IAAK,KAAK,QAAQ,EAAG,CACzC,IAAMC,EAASD,EACTE,EAA4B,CAAC,EACnCA,EAAK,YAAY,EAAIH,EACrBG,EAAK,aAAa,EAAID,EAAO,YAAY,KACzCH,EAAM,KAAK,CAAE,GAAGI,EAAM,GAAGD,CAAO,CAAC,CACnC,CACA,OAAOH,CACT,CAOA,WAAWK,EAAuB,CAAC,EAAS,CAC1C,eAAQ,MAAM,KAAK,QAAQ,EAAGA,CAAU,EACjC,IACT,CAEF,ECvOO,IAAMC,EAAN,cAAsC,KAAM,CACjD,aAAc,CACZ,MAAM,yEAAyE,CACjF,CACF,EAOaC,EAAN,cAAqC,KAAM,CAChD,YAAmBC,EAAuB,CACxC,MAAM,qCAAqCA,CAAa,GAAG,EAD1C,mBAAAA,CAEnB,CACF,ECDO,IAAMC,EAAN,KAAsD,CACnD,OACA,cAAqC,CAAC,EAEtC,QAMR,YAAYC,EAAuC,CAEjD,KAAK,OAASA,EAAM,OAEpB,KAAK,cAAgBA,EAAM,cAC3B,KAAK,QAAU,KAAK,OAAO,QAAQ,CACrC,CAMA,MAAoD,CAClD,IAAMC,EAAQ,KAAK,QAAQ,KAAK,EAC1B,CAAE,MAAAC,EAAO,KAAAC,CAAK,EAAIF,EACxB,GAAIE,EAAM,MAAO,CAAE,MAAAD,EAAO,KAAAC,CAAK,EAE/B,IAAMC,EAAWF,EAAM,CAAC,EAGxB,QAASG,EAAI,EAAGA,EAAI,KAAK,cAAc,OAAQA,IAAK,CAClD,IAAMC,EAAM,KAAK,cAAcD,CAAC,EAChCH,EAAM,KAAKI,EAAI,IAAIF,CAAQ,CAAC,CAC9B,CAEA,MAAO,CAAE,MAAOF,EAAc,KAAM,EAAM,CAC5C,CAKA,OAAQ,CACN,KAAK,QAAU,KAAK,OAAO,QAAQ,CACrC,CAKA,CAAC,OAAO,QAAQ,GAAI,CAAE,OAAO,IAAM,CAErC,EC3CO,IAAMK,EAAN,KAAmD,CAUxD,YACSC,KACJC,EACH,CAFO,SAAAD,EAGP,KAAK,OAAS,KAAK,IAAI,OAAOC,EAAW,CAAC,CAAC,EAC3C,QAASC,EAAI,EAAGA,EAAID,EAAW,OAAQC,IACrC,KAAK,cAAc,KAAK,KAAK,IAAI,OAAOD,EAAWC,CAAC,CAAC,CAAE,CAE3D,CAjBQ,OACA,cAAqC,CAAC,EAyB9C,YAAa,CACX,GAAI,KAAK,cAAc,SAAW,EAAG,OAAO,KAAK,OAAO,WAAW,EAEnE,GAAM,CAACC,EAAUC,CAAU,EAAI,KAAK,OAAO,WAAW,GAAK,CAAC,EAC5D,GAAID,IAAa,OAAW,OAE5B,IAAME,EAAiB,CAACF,EAAUC,CAAU,EAC5C,QAASF,EAAI,EAAGA,EAAI,KAAK,cAAc,OAAQA,IAC7CG,EAAQ,KAAK,KAAK,cAAcH,CAAC,EAAE,IAAIC,CAAQ,CAAC,EAGlD,OAAOE,CACT,CAYA,UAAW,CACT,IAAMF,EAAW,KAAK,OAAO,SAAS,EACtC,GAAI,KAAK,cAAc,SAAW,EAAG,OAAOA,EAC5C,GAAIA,IAAa,OAAW,OAE5B,IAAME,EAAiB,CAACF,CAAQ,EAChC,QAASD,EAAI,EAAGA,EAAI,KAAK,cAAc,OAAQA,IAC7CG,EAAQ,KAAK,KAAK,cAAcH,CAAC,EAAE,IAAIC,CAAQ,CAAC,EAGlD,OAAOE,CACT,CAYA,YAAa,CACX,GAAI,KAAK,cAAc,SAAW,EAAG,OAAO,KAAK,OAAO,WAAW,EAEnE,GAAM,CAACF,EAAUG,CAAQ,EAAI,KAAK,OAAO,WAAW,GAAK,CAAC,EAC1D,GAAIH,IAAa,OAAW,OAE5B,IAAME,EAAU,CAACC,CAAQ,EACzB,QAASJ,EAAI,EAAGA,EAAI,KAAK,cAAc,OAAQA,IAC7CG,EAAQ,KAAK,KAAK,cAAcH,CAAC,EAAE,IAAIC,CAAQ,CAAC,EAGlD,OAAOE,CACT,CAKA,IAAI,aAAc,CAChB,OAAO,KAAK,OAAO,IACrB,CAQA,iBAA0B,CACxB,OAAO,KAAK,IAAI,cAAc,GAAG,KAAK,OAAO,KAAK,CAAC,CACrD,CAOA,MAA8B,CAAE,OAAO,KAAK,OAAO,KAAK,CAAE,CAO1D,QAAwC,CACtC,IAAME,EAAS,KAAK,OACdC,EAAgB,KAAK,cACvBC,EAAeF,EAAO,KAAK,EAE/B,MAAO,CACL,MAA4C,CAC1C,IAAMG,EAAMD,EAAa,KAAK,EAC9B,GAAIC,EAAI,KAAM,MAAO,CAAE,MAAY,OAAW,KAAM,EAAK,EAEzD,IAAMP,EAAWO,EAAI,MAIfC,EAAQ,CAHOJ,EAAO,IAAIJ,CAAQ,CAGb,EAC3B,QAASD,EAAI,EAAGA,EAAIM,EAAc,OAAQN,IAAK,CAC7C,IAAMU,EAAMJ,EAAcN,CAAC,EAC3BS,EAAM,KAAKC,EAAI,IAAIT,CAAQ,CAAC,CAC9B,CAEA,MAAO,CAAE,MAAOQ,EAAc,KAAM,EAAM,CAC5C,EACA,OAAQ,CAAEF,EAAeF,EAAO,KAAK,CAAG,EACxC,CAAC,OAAO,QAAQ,GAAI,CAAE,OAAO,IAAM,CACrC,CACF,CAOA,SAAU,CAAE,OAAO,KAAK,OAAO,QAAQ,EAAE,CAAG,CAK5C,CAAC,OAAO,QAAQ,GAAI,CAClB,OAAO,IAAIM,EAAkB,IAAI,CACnC,CAEF,ECrKO,IAAMC,EAAN,MAAMC,CAAU,CAId,WAAa,IAAIC,EAEhB,OAAiB,EAmBzB,YAA6DC,EAAqC,CAChG,QAAWC,KAAkBD,EAAkB,CAE7C,GADsBC,EAAe,OACf,OAAW,MAAM,IAAIC,EAI3C,KAAK,WAAW,IAAID,EAAgB,IAAIE,CAAc,CACxD,CAGA,OAAO,IACT,CAaA,OAAUC,EAA2D,CACnE,IAAMC,EAAM,KAAK,WAAW,IAAID,CAAS,EACzC,GAAIC,IAAQ,OAAW,MAAM,IAAIC,EAAuBF,EAAU,IAAI,EACtE,OAAOC,CACT,CAaA,MAAME,EAA4D,CAAE,OAAO,KAAK,YAAYA,CAAY,CAAG,CAW3G,YAAYA,EAA4D,CACtE,IAAMC,EAAW,KAAK,OAAOD,CAAY,GAAG,SAAS,EACrD,GAAIC,IAAa,OAEjB,OAAO,KAAK,IAAIA,CAAQ,CAC1B,CAWA,aAAaD,EAAmE,CAC9E,IAAME,EAAW,KAAK,OAAOF,CAAY,GAAG,KAAK,EACjD,GAAIE,IAAa,OAEjB,MAAO,CAAC,GAAGA,CAAQ,EAAE,IAAIC,GAAK,KAAK,IAAIA,CAAC,CAAE,CAC5C,CAuBA,WAAWH,KAAsCI,EAAmC,CAClF,OAAIA,EAAW,SAAW,EAAU,KAAK,OAAOJ,CAAY,GAAG,WAAW,EAEnE,KAAK,SAASA,EAAcA,EAAc,GAAGI,CAAU,CAChE,CA4BA,SAASJ,KAAsCI,EAAmC,CAChF,IAAMH,EAAW,KAAK,OAAOD,CAAY,GAAG,SAAS,EAGrD,GAAI,UAAU,SAAW,EAAG,OAAOC,EACnC,GAAIA,IAAa,OAGjB,MAAO,CAACA,EAAU,GAAGG,EAAW,IAAID,GAAK,KAAK,UAAUF,EAAUE,CAAC,CAAC,CAAC,CACvE,CA4BA,WAAWH,KAAsCI,EAAmC,CAElF,GAAI,UAAU,SAAW,EAAG,OAAO,KAAK,OAAOJ,CAAY,GAAG,WAAW,EAGzE,GAAM,CAACC,EAAUI,CAAQ,EAAI,KAAK,OAAOL,CAAY,GAAG,WAAW,GAAK,CAAC,EACzE,GAAIC,IAAa,OAGjB,MAAO,CAACI,EAAU,GAAGD,EAAW,IAAID,GAAK,KAAK,UAAUF,EAAUE,CAAC,CAAC,CAAC,CACvE,CASQ,UAAaF,EAAkBJ,EAA6C,CAClF,IAAMC,EAAM,KAAK,WAAW,IAAID,CAAS,EACzC,GAAIC,IAAQ,OAAW,MAAM,IAAIC,EAAuBF,EAAU,IAAI,EAEtE,OAAOC,EAAI,IAAIG,CAAQ,CACzB,CAqBA,IAAIA,KAAqBG,EAAwE,CAE/F,OAAIA,EAAW,SAAW,EAAU,KAAK,UAAUH,EAAUG,EAAW,CAAC,CAAC,EAEtEA,EAAW,OAAS,EAAUA,EAAW,IAAID,GAAK,KAAK,UAAUF,EAAUE,CAAC,CAAC,EAE1E,CAAC,GAAG,KAAK,WAAW,OAAO,CAAC,EAChC,OAAOG,GAAKA,EAAE,IAAIL,CAAQ,CAAC,EAC3B,IAAIK,GAAKA,EAAE,IAAIL,CAAQ,CAAC,CAC7B,CAUA,IAAOA,EAAkBJ,EAAuC,CAE9D,IAAMC,EAAM,KAAK,WAAW,IAAID,CAAS,EACzC,OAAIC,IAAQ,OAAkB,GAEvBA,EAAI,IAAIG,CAAQ,CACzB,CAUA,OAAwCA,KAAqBG,EAAwB,CACnF,QAASG,EAAQ,EAAGA,EAAQH,EAAW,OAAQG,IAAS,CACtD,IAAMV,EAAYO,EAAWG,CAAK,EAC5BT,EAAM,KAAK,WAAW,IAAID,CAAS,EAEzC,GADIC,IAAQ,QACRA,EAAI,IAAIG,CAAQ,IAAM,GAAO,MAAO,EAC1C,CACA,MAAO,EACT,CAUA,OAAwCA,KAAqBG,EAAwB,CACnF,QAASG,EAAQ,EAAGA,EAAQH,EAAW,OAAQG,IAAS,CACtD,IAAMV,EAAYO,EAAWG,CAAK,EAC5BT,EAAM,KAAK,WAAW,IAAID,CAAS,EACzC,GAAIC,IAAQ,QACRA,EAAI,IAAIG,CAAQ,EAAG,MAAO,EAChC,CACA,MAAO,EACT,CASQ,UAA+BA,EAAkBO,EAAqB,CAE5E,IAAMV,EAAM,KAAK,WAAW,IAA0BU,EAAc,WAAY,EAChF,GAAIV,IAAQ,OAAW,MAAM,IAAIC,EAAuBS,EAAc,YAAY,IAAI,EAGtF,OAAAV,EAAI,IAAIG,EAAUO,CAAa,EAGxBA,CACT,CAsBA,IAAIP,KAAqBG,EAAkD,CACzE,OAAIA,EAAW,OAAS,EAAUA,EAAW,IAAID,GAAK,KAAK,UAAUF,EAAUE,CAAC,CAAC,EAG1E,KAAK,UAAUF,EAAUG,EAAW,CAAC,CAAC,CAC/C,CASA,OAAwCH,KAAqBG,EAAe,CAC1E,QAAWP,KAAaO,EACtB,KAAK,YAAYH,EAAUJ,CAAS,CAExC,CAWA,YAAYI,EAAkBJ,EAAgC,CAE5D,IAAMY,EAAY,KAAK,WAAW,IAAIZ,CAAS,EAG/C,GAAIY,IAAc,OAAW,MAAM,IAAIV,EAAuBF,EAAU,IAAI,EAI5E,OADeY,EAAU,IAAIR,CAAQ,IACtB,OAAkB,GAG1BQ,EAAU,OAAOR,CAAQ,CAClC,CAYA,iBAAiBS,EAA6B,CAC5C,IAAIC,EAAe,EACnB,QAASJ,EAAQ,EAAGA,EAAQG,EAAU,OAAQH,IAAS,CACrD,IAAMN,EAAWS,EAAUH,CAAK,EAChC,QAAWT,KAAO,KAAK,WAAW,OAAO,EACnCA,EAAI,IAAIG,CAAQ,IAClBH,EAAI,OAAOG,CAAQ,EACnBU,IAGN,CACA,OAAOA,CACT,CAUA,WAAoB,CAClB,YAAK,SACE,KAAK,MACd,CAMA,OAAQ,CACN,YAAK,WAAW,MAAM,EACtB,KAAK,OAAS,EACP,IACT,CAMA,iBAAkB,CAChB,YAAK,WAAW,QAAQR,GAAKA,EAAE,MAAM,CAAC,EACtC,KAAK,OAAS,EACP,IACT,CAyBA,SACEH,KACGI,EACH,CACA,OAAO,IAAIQ,EAAkB,IAAIC,EAAe,KAAMb,EAAc,GAAGI,CAAU,CAAC,CACpF,CAyBA,MACEJ,KACGI,EACH,CACA,OAAO,IAAIS,EAAe,KAAMb,EAAc,GAAGI,CAAU,CAC7D,CAiBA,WAAWA,EAAuB,CAAC,EAAGU,EAAuB,CAAC,EAAG,CAC/D,YAAK,WAAW,QAAQ,CAAChB,EAAKiB,IAAQ,EAChCX,EAAW,SAAW,GAAKA,EAAW,SAASW,CAAG,IACpD,QAAQ,MAAMjB,EAAI,QAAQ,EAAGgB,CAAU,CAE3C,CAAC,EACM,IACT,CAaA,YAAYb,EAAkBa,EAAuB,CAAC,EAAG,CACvD,QAAWhB,KAAO,KAAK,WAAW,OAAO,EAAG,CAC1C,GAAIA,EAAI,IAAIG,CAAQ,IAAM,GAAO,SAEjC,IAAMe,EAAOlB,EAAI,IAAIG,CAAQ,EACvBgB,EAAU,CACd,cAAeD,EAAK,YAAY,KAChC,GAAGA,CACL,EACA,QAAQ,MAAM,CAAE,CAACf,CAAQ,EAAGgB,CAAQ,EAAGH,CAAU,CACnD,CAEA,OAAO,IACT,CAUA,OAAO,MAAMI,EAAyB,CAUpC,OATiB,KAAK,MAAMA,EAAM,SAAUH,EAAaI,EAAY,CACnE,OAAIA,EAAM,eAAe,YAAY,GACnC,QAAQ,eAAeA,EAAO5B,EAAU,SAAS,EAC1C4B,GAELA,EAAM,eAAeC,CAAe,EAAU,IAAIxB,EAAauB,EAAM,QAAQ,EAC7EA,EAAM,eAAeE,CAAsB,EAAU,IAAI7B,EAAoB2B,EAAM,QAAQ,EACxF,KAAKJ,CAAG,CACjB,CAAC,CAEH,CAQA,OAAO,kBAAkBO,EAAuB,CAAC,EAAG,CAClD,IAAMC,EAAe,CACnB,IAAIC,EAAaC,EAAiB,CAChC,IAAMC,EAAcF,EAAOC,CAAO,EAElC,OAAI,OAAOC,GAAgB,aAAeJ,EAAW,SAAW,GAAKA,EAAW,SAASG,CAAO,GACvF,YAAwBE,EAAa,CAC1C,eAAQ,eAAe,YAAaF,EAASE,CAAI,EACjD,QAAQ,MAAM,EACd,QAAQ,SAAS,EACVD,EAAY,MAAM,KAAMC,CAAI,CACrC,EAGKD,CACT,CACF,EAEA,OAAO,IAAI,MAAM,IAAInC,EAAagC,CAAY,CAChD,CAEF,EC1kBO,IAAMK,EAAM,IAAIC,EAEnB,OAAO,OAAW,IAEpB,OAAO,IAAMD,EACJ,OAAO,OAAW,KAAe,SAAW,OAErD,OAAO,QAAU,CAAE,IAAAA,CAAI",
6
- "names": ["ComponentMapKey", "ComponentClassesMapKey", "hashString", "str", "hash", "i", "char", "ComponentClassesMap", "entries", "i", "entry", "componentClass", "index", "map", "hashString", "hash", "existingIndex", "hashId", "lastIndex", "lastHash", "callback", "instances", "hashes", "value", "ComponentClassesMapKey", "ComponentMap", "entries", "i", "entry", "entityId", "component", "index", "lastIdx", "lastEntity", "callback", "entities", "instances", "result", "ComponentMapKey", "table", "key", "value", "entity", "meta", "properties", "ComponentTypeKeyMissing", "ComponentNotRegistered", "componentName", "ComponentIterator", "query", "entry", "value", "done", "entityId", "i", "map", "ComponentQuery", "ecs", "components", "i", "entityId", "entryValue", "results", "keyValue", "keyMap", "componentMaps", "keysIterator", "key", "value", "map", "ComponentIterator", "EntityMap", "_EntityMap", "ComponentClassesMap", "componentClasses", "componentClass", "ComponentTypeKeyMissing", "ComponentMap", "component", "map", "ComponentNotRegistered", "keyComponent", "entityId", "entities", "x", "components", "keyValue", "v", "index", "componentData", "entityMap", "entityIds", "deletedCount", "ComponentIterator", "ComponentQuery", "properties", "key", "data", "columns", "json", "value", "ComponentMapKey", "ComponentClassesMapKey", "funcFilter", "traceHandler", "target", "propKey", "targetValue", "args", "ecs", "EntityMap"]
4
+ "sourcesContent": ["/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n/**\n * Property key used for ComponentMap identification during serialization\n * @category Constants\n */\nexport const ComponentMapKey = \"ComponentMap\"\n\n/**\n * Property key used for ComponentClassesMap identification during serialization\n * @category Constants\n */\nexport const ComponentClassesMapKey = \"ComponentClassesMap\"\n\n/**\n * Variadic type helper that preserves the strongly typed parameter interfaces used by the compiler and intellisense.\n * Works with single returned types or spread array returned types.\n * @category Types\n */\nexport type SingleOrArray<T extends any[]> =\n // return a single variadic item when only 1 item is specified\n T['length'] extends 1 ? T[0]\n // otherwise return an array of variadic types\n : { [Index in keyof T]: T[Index] }\n\n/**\n * Used to return component instance data.\n * \n * Note: This is not used for registering components or extending component classes\n * @category Types\n */\nexport interface Component { }\n\n/**\n * @category Types\n * @example\n * \n * class PositionComponent {\n * constructor(x, y) {\n * this.x = x;\n * this.y = y;\n * }\n * }\n */\nexport type ComponentClass<ComponentInstance> = (new (...args: any[]) => ComponentInstance) & {\n // static property\n hashId?: number;\n};\n\n/**\n* Used for inferring generic type spread for classes\n* @category Types\n*/\nexport type ComponentClasses<T extends Component[]> =\n { [Index in keyof T]: ComponentClass<T[Index]> }\n\n/**\n * Custom iterator interface that includes a reset function\n * @category Types\n */\nexport type Iterator<T> = {\n /**\n * Gets the next result in the iteration\n */\n next: () => IteratorResult<T>\n /**\n * Resets the iterator back to the beginning\n */\n reset: () => void\n /**\n * Returns the iterator instance\n */\n [Symbol.iterator]: () => Iterator<T>\n}\n\n/**\n * Helper type for late-bound iterator assignment with IntelliSense support\n * @category Types\n * @example\n * \n * let someIterator: IComponentIterator<[Player, Position]>\n * \n * // assignment made somewhere else in the code\n * const [player, position] = someIterator(Player, Position) ?? []\n * position?.x = 123 // position will have IntelliSense\n */\nexport type IComponentIterator<T extends Component[]>\n = Iterator<ComponentClasses<[number, ...T]>>", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n/**\n * Generates a 32-bit integer hash from a string\n * @param str - The string to hash\n * @returns A 32-bit integer hash\n */\nexport function hashString(str: string) {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash |= 0; // Convert to 32bit\n }\n return hash;\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport type { ComponentMap } from './component-map.js';\nimport {\n ComponentClassesMapKey,\n type ComponentClass,\n type Iterator,\n} from './types.js';\nimport { hashString } from './utils.js';\n\n/**\n * Component class map for storing registered component maps\n * @category Maps\n */\nexport class ComponentClassesMap {\n\n private hashIdToName: Map<number, string> = new Map<number, string>()\n private hashIdToIndex = new Map<number, number>();\n private indexToHashId: number[] = [];\n private maps: ComponentMap<any>[] = [];\n\n /**\n * Creates a new component classes map\n * @param entries - Optional initial data for the map\n */\n constructor(entries?: readonly (readonly [number, ComponentMap<any>])[] | null) {\n if (entries) {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n this.setByHashId(entry[0], entry[1]);\n }\n }\n }\n\n /**\n * Returns the number of registered component maps\n */\n get size() {\n return this.maps.length;\n }\n\n /**\n * Clears all maps and internal indices while preserving array references\n */\n clear(): void {\n this.maps.length = 0;\n this.indexToHashId.length = 0;\n this.hashIdToIndex.clear();\n }\n\n /**\n * Retrieves a component map using the component class\n * @param componentClass - The component class to get the map for\n * @returns The {@link ComponentMap} for the specified class, or undefined if not found\n */\n get<T>(componentClass: ComponentClass<T>): ComponentMap<T> | undefined {\n const index = this.hashIdToIndex.get(componentClass.hashId!);\n return index !== undefined ? this.maps[index] : undefined;\n }\n\n /**\n * Registers a component map. Automatically generates a hashId from the class name if missing\n * @param componentClass - The component class to register\n * @param map - The {@link ComponentMap} instance to store\n * @returns The {@link ComponentClassesMap} instance for chaining\n */\n set<T>(componentClass: ComponentClass<T>, map: ComponentMap<T>): this {\n if (componentClass.hashId === undefined) {\n componentClass.hashId = hashString(componentClass.name);\n }\n\n this.hashIdToName.set(componentClass.hashId, componentClass.name);\n return this.setByHashId(componentClass.hashId!, map);\n }\n\n /**\n * Maps a specific numeric hash id to a component map instance.\n * @param hash - The numeric hash id\n * @param map - The {@link ComponentMap} instance to store\n * @returns The {@link ComponentClassesMap} instance for chaining\n */\n setByHashId(hash: number, map: ComponentMap<any>): this {\n const existingIndex = this.hashIdToIndex.get(hash);\n\n if (existingIndex !== undefined) {\n this.maps[existingIndex] = map;\n } else {\n this.hashIdToIndex.set(hash, this.maps.length);\n this.indexToHashId.push(hash);\n this.maps.push(map);\n }\n\n return this;\n }\n\n /**\n * Removes a component map and re-orders internal storage to maintain density\n * @param componentClass - The component class to remove the map for\n * @returns True if the map was removed, otherwise false\n */\n delete(componentClass: ComponentClass<any>): boolean {\n const hashId = componentClass.hashId!;\n const index = this.hashIdToIndex.get(hashId);\n if (index === undefined) return false;\n\n const lastIndex = this.maps.length - 1;\n const lastHash = this.indexToHashId[lastIndex];\n\n // Swap\n this.maps[index] = this.maps[lastIndex];\n this.indexToHashId[index] = lastHash;\n\n // Update map pointer\n this.hashIdToIndex.set(lastHash, index);\n\n // Pop\n this.maps.pop();\n this.indexToHashId.pop();\n this.hashIdToIndex.delete(hashId);\n return true;\n }\n\n /**\n * Executes a callback for every map, providing the instance and its registered name\n * @param callback - The callback to execute\n */\n forEach(callback: (value: ComponentMap<any>, name: string) => void) {\n for (let i = 0; i < this.maps.length; i++) {\n callback(this.maps[i], this.hashIdToName.get(this.indexToHashId[i])!);\n }\n }\n\n /**\n * Returns an iterator of all component map instances \n * @returns An {@link ArrayIterator} of {@link ComponentMap} instances\n */\n values(): ArrayIterator<ComponentMap<any>> { return this.maps.values() }\n\n /**\n * Returns an iterator of [hashId, componentMap] pairs\n * @returns An {@link Iterator} instance\n */\n entries(): Iterator<[number, ComponentMap<any>]> {\n let index = 0;\n const instances = this.maps;\n const hashes = this.indexToHashId;\n\n return {\n next(): IteratorResult<[number, ComponentMap<any>]> {\n if (index < instances.length) {\n const value: [number, ComponentMap<any>] = [hashes[index], instances[index]];\n index++;\n return { value, done: false };\n }\n return { value: undefined as any, done: true };\n },\n reset() { index = 0; },\n [Symbol.iterator]() { return this; }\n };\n }\n\n /**\n * Called when using JSON.stringify\n * @returns An object representation for serialization\n */\n toJSON() {\n return { [ComponentClassesMapKey]: 1, iterable: [...this.entries()] };\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport {\n ComponentMapKey,\n type Iterator\n} from './types.js';\n\n/**\n * Component map for storing entity ids and related component data\n * @category Maps\n */\nexport class ComponentMap<TComponentInstance> implements Iterable<[number, TComponentInstance]> {\n\n private indices: number[] = [];\n\n private entities: number[] = [];\n\n private instances: TComponentInstance[] = [];\n\n /**\n * Creates a new component map\n * @param entries - Optional initial data for the map\n */\n constructor(entries?: readonly (readonly [number, TComponentInstance])[] | null) {\n if (entries) {\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n this.set(entry[0], entry[1]);\n }\n }\n }\n\n /**\n * Returns the number of entities in the map\n */\n get size() {\n return this.instances.length;\n }\n\n /**\n * Clears all component data from the map\n */\n clear() {\n this.indices = [];\n this.entities.length = 0;\n this.instances.length = 0;\n }\n\n /**\n * Adds or updates component data for an entity\n * @param entityId - The entity id to set\n * @param component - The component data to set\n */\n set(entityId: number, component: TComponentInstance) {\n if (this.has(entityId)) {\n this.instances[this.indices[entityId]] = component;\n return;\n }\n this.indices[entityId] = this.instances.length;\n this.entities.push(entityId);\n this.instances.push(component);\n }\n\n /**\n * Gets the component data for an entity\n * @param entityId - The entity id to get\n * @returns The component data, or undefined if not found\n */\n get(entityId: number) {\n const index = this.indices[entityId];\n return index !== undefined && this.entities[index] === entityId\n ? this.instances[index]\n : undefined;\n }\n\n /**\n * Removes component data for an entity\n * @param entityId - The entity id to remove\n * @returns True if the component was removed, otherwise false\n */\n delete(entityId: number) {\n const index = this.indices[entityId];\n if (index === undefined || index === -1 || this.entities[index] !== entityId) return false;\n\n // swap and pop with last element to keep dense\n const lastIdx = this.instances.length - 1;\n const lastEntity = this.entities[lastIdx];\n this.instances[index] = this.instances[lastIdx];\n this.entities[index] = lastEntity;\n this.indices[lastEntity] = index;\n this.instances.pop();\n this.entities.pop();\n\n // invalidate index\n this.indices[entityId] = -1;\n\n return true;\n }\n\n /**\n * Checks if an entity has a component in this map\n * @param entityId - The entity id to check\n * @returns True if the entity has a component, otherwise false\n */\n has(entityId: number) {\n const index = this.indices[entityId];\n return index !== undefined && index !== -1 && this.entities[index] === entityId;\n }\n\n /**\n * Executes a callback for every map, providing the component data and its entity id\n * @param callback - The callback to execute\n */\n forEach(callback: (value: TComponentInstance, key: number) => void) {\n for (let i = 0; i < this.instances.length; i++) {\n callback(this.instances[i], this.entities[i]);\n }\n }\n\n /**\n * Returns the first entry\n * @returns A tuple of [entityId, componentData], or undefined if empty\n */\n firstEntry(): [entityId: number, value: TComponentInstance] | undefined {\n return this.entities.length === 0\n ? undefined\n : [this.entities[0], this.instances[0]];\n }\n\n /**\n * Returns the first entity id\n * @returns The first entity id, or undefined if empty\n */\n firstKey(): number | undefined {\n return this.entities.length === 0\n ? undefined\n : this.entities[0];\n }\n\n /**\n * Returns the first entity data\n * @returns The first component data, or undefined if empty\n */\n firstValue(): TComponentInstance | undefined {\n return this.instances.length === 0\n ? undefined\n : this.instances[0];\n }\n\n /**\n * Returns an iterator of [entityId, componentData] pairs\n * @returns An {@link Iterator} instance\n */\n [Symbol.iterator](): Iterator<[number, TComponentInstance]> {\n return this.entries();\n }\n\n /**\n * Returns an iterator of all entity ids\n * @returns An {@link ArrayIterator} of entity ids\n */\n keys(): ArrayIterator<number> {\n return this.entities.values();\n }\n\n /**\n * Returns an iterator of all component data\n * @returns An {@link ArrayIterator} of component data\n */\n values(): ArrayIterator<TComponentInstance> {\n return this.instances.values();\n }\n\n /**\n * Returns an iterator of [entityId, componentData] pairs\n * @returns An {@link Iterator} instance\n */\n entries(): Iterator<[number, TComponentInstance]> {\n let index = 0;\n const entities = this.entities;\n const instances = this.instances;\n\n return {\n next(): IteratorResult<[number, TComponentInstance]> {\n if (index < instances.length) {\n const result: IteratorResult<[number, TComponentInstance]> = {\n value: [entities[index], instances[index]],\n done: false\n };\n index++;\n return result;\n }\n return { value: <any>undefined, done: true };\n },\n reset() {\n index = 0;\n },\n [Symbol.iterator]() {\n return this;\n },\n };\n }\n\n /**\n * Called when using JSON.stringify\n * @returns An object representation for serialization\n */\n toJSON() {\n return { [ComponentMapKey]: 1, iterable: [...this.entries()] };\n }\n\n /**\n * Returns an array of objects for tabular display\n * @returns An array of objects formatted for {@link console.table}\n */\n toTable(): any[] {\n const table = []\n for (const [key, value] of this.entries()) {\n const entity = value as { new(): TComponentInstance };\n const meta: Record<string, any> = {};\n meta[\"entity.key\"] = key;\n meta[\"entity.type\"] = entity.constructor.name;\n table.push({ ...meta, ...entity });\n }\n return table;\n }\n\n /**\n * Prints entity data in a tabular format to the console\n * @param properties - Optional filter. Specifies which property columns to display in the tables.\n * @returns The {@link ComponentMap} instance for chaining\n */\n printTable(properties: string[] = []): this {\n console.table(this.toTable(), properties);\n return this;\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n/**\n * Thrown when trying to register a component that is missing a 'name' parameter\n * @category Errors\n */\nexport class ComponentTypeKeyMissing extends Error {\n constructor() {\n super(`Component type is missing the 'name' parameter. i.e. a constructor name`);\n }\n}\n\n/**\n * Thrown when trying to access a component that has not been registered\n * @param componentName - The name of the unregistered component\n * @category Errors\n */\nexport class ComponentNotRegistered extends Error {\n constructor(public componentName: string) {\n super(`Component map does not exist for '${componentName}'`);\n }\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport type { ComponentMap } from './component-map.js';\nimport type { ComponentQuery } from './query.js';\n\n/**\n * An iterator for yielding entity ids and their associated component data\n * @category Iterators\n * @example\n * // construct an instance\n * const iterator = new ComponentIterator(new ComponentQuery(entityMap, Player, Position))\n * \n * // iterate component data that is related to the Player\n * for(const [entityId, player, position] of iterator) { }\n * \n * // you can also reset the iterator back to the start\n * // without having to create a new ComponentIterator instance\n * iterator.reset()\n * for(const [entityId, player, position] of iterator) { }\n */\nexport class ComponentIterator<TKey, TRelated extends any[]> {\n private keyMap: ComponentMap<TKey>;\n private componentMaps: ComponentMap<any>[] = [];\n // iteration state\n private entries: Iterator<[number, TKey]>;\n\n /**\n * Creates a new component iterator\n * @param query - The {@link ComponentQuery} to iterate over\n */\n constructor(query: ComponentQuery<TKey, TRelated>) {\n // @ts-ignore internal private var accessor\n this.keyMap = query.keyMap\n // @ts-ignore internal private var accessor\n this.componentMaps = query.componentMaps\n this.entries = this.keyMap.entries();\n }\n\n /**\n * Gets the next iterator value\n * @returns An {@link IteratorResult} containing the next [entityId, keyComponentData, ...relatedComponentData] tuple\n */\n next(): IteratorResult<[number, TKey, ...TRelated]> {\n const entry = this.entries.next();\n const { value, done } = entry;\n if (done) return { value, done };\n\n const entityId = value[0];\n\n // append the related components\n for (let i = 0; i < this.componentMaps.length; i++) {\n const map = this.componentMaps[i];\n value.push(map.get(entityId));\n }\n\n return { value: value as any, done: false };\n }\n\n /**\n * Resets the iterator back to the first entry\n */\n reset() {\n this.entries = this.keyMap.entries();\n }\n\n /**\n * Returns this iterator instance\n */\n [Symbol.iterator]() { return this; }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport type { ComponentMap } from './component-map.js';\nimport type { EntityMap } from './entity-map.js';\nimport { ComponentIterator } from './iterator.js';\nimport type { ComponentClass, ComponentClasses, Iterator, SingleOrArray } from './types.js';\n\n/**\n * A reusable query for retrieving entities and their components\n * @category Queries\n * @example\n * const query = ecs.query(Player, Position)\n * \n * // get the first entry\n * const [playerId, player, position] = query.firstEntry() ?? []\n * \n * // get the first key\n * const [playerId, position] = query.firstKey() ?? []\n * \n * // get the first value\n * const [player, position] = query.firstValue() ?? []\n * \n * // iterate\n * for (const [playerId, player, position] of query) {\n * \n * }\n */\nexport class ComponentQuery<TKey, TRelated extends any[]> {\n private keyMap: ComponentMap<TKey>\n private componentMaps: ComponentMap<any>[] = []\n\n /**\n * Creates a new component query\n * @param ecs - The {@link EntityMap} instance to query\n * @param components - The first component class <TKey> is the primary component. Optional additional component classes <TRelated> to retrieve for each entity.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n */\n constructor(\n public ecs: EntityMap,\n ...components: [ComponentClass<TKey>, ...ComponentClasses<TRelated>]\n ) {\n this.keyMap = this.ecs.getMap(components[0])!;\n for (let i = 1; i < components.length; i++) {\n this.componentMaps.push(this.ecs.getMap(components[i])!)\n }\n }\n\n /**\n * Gets the first entry matching the query.\n * \n * Includes the entity id, the key component data, and any related component data.\n * @returns A tuple of `[entityId, keyComponentData, ...relatedComponentData]`, or `undefined` if no entities match.\n */\n firstEntry(): [number, TKey, ...TRelated] | undefined;\n firstEntry() {\n if (this.componentMaps.length === 0) return this.keyMap.firstEntry()\n\n const [entityId, entryValue] = this.keyMap.firstEntry() ?? []\n if (entityId === undefined) return undefined;\n\n const results: any[] = [entityId, entryValue]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Gets the first key matching the query.\n * \n * @returns The entity id if no related components were specified in the constructor.\n * \n * Otherwise, a tuple of `[entityId, ...relatedComponentData]`.\n * \n * Returns `undefined` if no entities match.\n */\n firstKey(): SingleOrArray<[number, ...TRelated]> | undefined;\n firstKey() {\n const entityId = this.keyMap.firstKey()\n if (this.componentMaps.length === 0) return entityId;\n if (entityId === undefined) return undefined;\n\n const results: any[] = [entityId]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Get the first component data matching the query.\n * \n * @returns The key component data if no related components were specified in the constructor.\n * \n * Otherwise, a tuple of `[keyComponentData, ...relatedComponentData]`.\n * \n * Returns `undefined` if no entities match.\n */\n firstValue(): SingleOrArray<[TKey, ...TRelated]> | undefined;\n firstValue() {\n if (this.componentMaps.length === 0) return this.keyMap.firstValue()\n\n const [entityId, keyValue] = this.keyMap.firstEntry() ?? []\n if (entityId === undefined) return undefined;\n\n const results = [keyValue]\n for (let i = 0; i < this.componentMaps.length; i++) {\n results.push(this.componentMaps[i].get(entityId));\n }\n\n return results\n }\n\n /**\n * Returns the count of entities matching the query\n * @returns The number of entities that have the key component\n */\n get entityCount() {\n return this.keyMap.size\n }\n\n /**\n * Destroys all entities matching the query\n * @returns The total number of components destroyed across all affected entities\n * @example\n * const destroyedCount = query.destroyEntities()\n */\n destroyEntities(): number {\n return this.ecs.destroyEntity(...this.keyMap.keys())\n }\n\n /**\n * Gets all entity ids matching the query.\n * \n * @returns An {@link ArrayIterator} of entity ids.\n */\n keys(): ArrayIterator<number> { return this.keyMap.keys() }\n\n /**\n * Gets all component data matching the query.\n *\n * @returns An {@link Iterator} of `[keyComponentData, ...relatedComponentData]` tuples containing component data\n * @example\n * const query = ecs.query(Player, Position)\n * for (const [player, position] of query.values()) { }\n */\n values(): Iterator<[TKey, ...TRelated]> {\n const keyMap = this.keyMap;\n const componentMaps = this.componentMaps;\n let keysIterator = keyMap.keys();\n\n return {\n next(): IteratorResult<[TKey, ...TRelated]> {\n const key = keysIterator.next();\n if (key.done) return { value: <any>undefined, done: true };\n\n const entityId = key.value;\n const keyComponent = keyMap.get(entityId);\n\n // append the related components\n const value = [keyComponent];\n for (let i = 0; i < componentMaps.length; i++) {\n const map = componentMaps[i];\n value.push(map.get(entityId));\n }\n\n return { value: value as any, done: false };\n },\n reset() { keysIterator = keyMap.keys(); },\n [Symbol.iterator]() { return this; },\n };\n }\n\n /**\n * Gets all component data entries matching the query\n * \n * @returns A {@link ComponentIterator} instance that yields `[entityId, keyComponentData, ...relatedComponentData]`\n * @example\n * const query = ecs.query(Player, Position)\n * for (const [entityId, player, position] of query.entries()) { }\n */\n entries() { return this[Symbol.iterator](); }\n\n /**\n * @returns A {@link ComponentIterator} instance that yields `[entityId, keyComponentData, ...relatedComponentData]`\n */\n [Symbol.iterator]() {\n return new ComponentIterator(this);\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { ComponentClassesMap } from './component-classes.js';\nimport { ComponentMap } from './component-map.js';\nimport { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js';\nimport { ComponentIterator } from './iterator.js';\nimport { ComponentQuery } from './query.js';\nimport {\n ComponentClassesMapKey,\n ComponentMapKey,\n type Component,\n type ComponentClass,\n type ComponentClasses,\n type SingleOrArray\n} from './types.js';\n\n/**\n * Class for storing entities and their relationships.\n * @category Maps\n */\nexport class EntityMap {\n /**\n * Registered component classes that contain the component data\n */\n public components = new ComponentClassesMap()\n\n private nextId: number = 0\n\n private freeIds: number[] = []\n\n /**\n * Registers component classes with the {@link EntityMap}\n * @param componentClasses - One or more component classes to register\n * @returns The {@link EntityMap} instance for chaining\n * @throws {@link ComponentTypeKeyMissing} when the specified component type is missing a 'name' parameter\n * @example\n * // component class\n * class MyComponent {\n * constructor(x) {\n * this.x = x;\n * }\n * }\n *\n * ecs.register(MyComponent);\n * // or multiple\n * ecs.register(MyComponent1, MyComponent2);\n */\n register<TComponentClasses extends ComponentClass<any>[]>(...componentClasses: TComponentClasses) {\n for (const componentClass of componentClasses) {\n const componentName = componentClass.name;\n if (componentName === undefined) throw new ComponentTypeKeyMissing();\n\n // create the component map\n // const componentDataMap: ComponentMap<any> = new ComponentMap();\n this.components.set(componentClass, new ComponentMap());\n }\n\n // chain\n return this;\n }\n\n /**\n * Gets a component class map\n * @param component - The component class to get the map for\n * @returns The {@link ComponentMap} for the specified component, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * const positionMap = ecs.getMap(Position)\n * for(const [entityId, position] of positionMap) {\n * position.x += 1\n * }\n */\n getMap<T>(component: ComponentClass<T>): ComponentMap<T> | undefined {\n const map = this.components.get(component);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n return map\n }\n\n /**\n * @deprecated Use {@link EntityMap.firstEntity} instead\n * \n * Returns an array of component data for the first entity associated with the keyComponent\n * @param keyComponent - The component class used to find the first entity\n * @returns An array of components for the first entity, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // get the first entity\n * const playerEntity = ecs.first(Player) ?? []\n */\n first(keyComponent: ComponentClass<any>): Component[] | undefined { return this.firstEntity(keyComponent); }\n\n /**\n * Returns an array of component data for the first entity associated with the keyComponent\n * @param keyComponent - The component class used to find the first entity\n * @returns An array of components for the first entity, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // get the first entity\n * const playerEntity = ecs.firstEntity(Player) ?? []\n */\n firstEntity(keyComponent: ComponentClass<any>): Component[] | undefined {\n const entityId = this.getMap(keyComponent)?.firstKey();\n if (entityId === undefined) return undefined;\n\n return this.get(entityId);\n }\n\n /**\n * Returns an array of component data arrays associated with the keyComponent\n * @param keyComponent - The component class used to find the entities\n * @returns An array of component arrays, or undefined if the key component map is not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // get an array of component arrays: e.g. [[Player, Position, Velocity], [Player, Position, Velocity], ...]\n * const entities = ecs.entityValues(Player) ?? []\n */\n entityValues(keyComponent: ComponentClass<any>): Array<Component[]> | undefined {\n const entities = this.getMap(keyComponent)?.keys();\n if (entities === undefined) return undefined;\n\n return [...entities].map(x => this.get(x)!)\n }\n\n /**\n * Gets the first entity entry for a component class\n * @param keyComponent - The component class to find the first entry for\n * @param components - Additional component classes to retrieve for the same entity\n * @returns A tuple containing the entity id followed by the component data, or undefined if not found\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * // return the first entry\n * const [entityId, player] = ecs.firstEntry(Player) ?? []\n * \n * // or return multiple related components in addition to the first entry\n * const [entityId, player, position, direction] = ecs.firstEntry(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstEntry<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ): [number, TKey, ...TRelated] | undefined;\n firstEntry(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n if (components.length === 0) return this.getMap(keyComponent)?.firstEntry()\n\n return this.firstKey(keyComponent, keyComponent, ...components);\n }\n\n /**\n * Gets the first entity id for a component class \n * and optionally any related component data\n * @param keyComponent - The component class used to find the first entity\n * @param components - Additional component classes to retrieve for the same entity\n * @returns If only keyComponent is provided, returns the entity id. \n * \n * If related components are provided, returns a tuple with the id and component data. \n * \n * Returns undefined if not found.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first entity id\n * const entityId = ecs.firstKey(Player)\n * \n * // or return multiple related component in addition to entity id\n * const [entityId, position, direction] = ecs.firstKey(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstKey<TKey, TRelated extends any[]>(\n keyComponent: TKey,\n ...components: ComponentClasses<TRelated>\n ): SingleOrArray<[number, ...TRelated]> | undefined;\n firstKey(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n const entityId = this.getMap(keyComponent)?.firstKey();\n\n // single component key\n if (arguments.length === 1) return entityId;\n if (entityId === undefined) return undefined;\n\n // attach related component data\n return [entityId, ...components.map(x => this.getEntity(entityId, x))];\n }\n\n /**\n * Gets the first entity component data for a component class\n * and optionally any related component data\n * @param keyComponent - The component class used to find the first entity\n * @param components - Additional component classes to retrieve for the same entity\n * @returns If only keyComponent is provided, returns the component data. \n * \n * If related components are provided, returns a tuple with all component data. \n * \n * Returns undefined if not found.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // return the first component data\n * const player = ecs.firstValue(Player)\n * \n * // or multiple related data in addition to the first component\n * const [player, position, direction] = ecs.firstValue(\n * Player,\n * Position,\n * Direction\n * ) ?? []\n */\n firstValue<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ): SingleOrArray<[TKey, ...TRelated]> | undefined;\n firstValue(keyComponent: ComponentClass<any>, ...components: ComponentClass<any>[]) {\n // single component\n if (arguments.length === 1) return this.getMap(keyComponent)?.firstValue();\n\n // get the first entry\n const [entityId, keyValue] = this.getMap(keyComponent)?.firstEntry() ?? [];\n if (entityId === undefined) return undefined;\n\n // attach related components\n return [keyValue, ...components.map(x => this.getEntity(entityId, x))]\n }\n\n /**\n * Internal helper to get component data for an entity\n * @param entityId - The entity id to get the component for\n * @param component - The component class to get the data of\n * @returns The component data if it exists, otherwise undefined\n * @throws {@link ComponentNotRegistered} when the specified component is not registered \n */\n private getEntity<T>(entityId: number, component: ComponentClass<T>): T | undefined {\n const map = this.components.get(component);\n if (map === undefined) throw new ComponentNotRegistered(component.name)\n\n return map.get(entityId);\n }\n\n /**\n * Gets component data related to an entity id\n * @param entityId - The entity id to get component(s) for\n * @param components - One or more component classes to retrieve. If none provided, retrieves all components for the entity.\n * @returns Depending on parameters: a single component, an array of specified components, or an array of all components for the entity.\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // get one by id\n * const player = ecs.get(entityId, Player)\n * \n * // get multiple by id\n * const [player, position] = ecs.get(entityId, Player, Position) ?? []\n * \n * // get all by id\n * const playerEntity = ecs.get(entityId) ?? []\n */\n get(entityId: number): Component[] | undefined;\n get<T>(entityId: number, component: ComponentClass<T>): T | undefined;\n get<T extends any[]>(entityId: number, ...components: ComponentClasses<T>): SingleOrArray<T> | undefined;\n get(entityId: number, ...components: ComponentClasses<any>): Component | Component[] | undefined {\n // return a single component\n if (components.length === 1) return this.getEntity(entityId, components[0]);\n // return filtered components\n if (components.length > 1) return components.map(x => this.getEntity(entityId, x));\n // return all components\n return [...this.components.values()]\n .filter(v => v.has(entityId))\n .map(v => v.get(entityId));\n }\n\n /**\n * Check if a component exists for an entity\n * @param entityId - The entity id to check for the component\n * @param component - The component class to check\n * @returns True if the entity has the component, otherwise false\n * @example\n * const exists = ecs.has(entityId, Position)\n */\n has<T>(entityId: number, component: ComponentClass<T>): boolean {\n // get the component map\n const map = this.components.get(component);\n if (map === undefined) return false\n\n return map.has(entityId);\n }\n\n /**\n * Checks if all of the specified components exist for an entity\n * @param entityId - The entity id to check\n * @param components - One or more component classes to check for\n * @returns True if the entity has ALL specified components, otherwise false\n * @example\n * const hasAll = ecs.hasAll(entityId, Position, Velocity)\n */\n hasAll<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component);\n if (map === undefined) return false;\n if (map.has(entityId) === false) return false;\n }\n return true\n }\n\n /**\n * Checks if any of the specified components exist for an entity\n * @param entityId - The entity id to check\n * @param components - One or more component classes to check for\n * @returns True if the entity has ANY of the specified components, otherwise false\n * @example\n * const hasAny = ecs.hasAny(entityId, Position, Velocity)\n */\n hasAny<T extends ComponentClass<any>[]>(entityId: number, ...components: T): boolean {\n for (let index = 0; index < components.length; index++) {\n const component = components[index];\n const map = this.components.get(component);\n if (map === undefined) continue;\n if (map.has(entityId)) return true;\n }\n return false\n }\n\n /**\n * Internal helper to set component data for an entity\n * @param entityId - The entity id to set the component for\n * @param componentData - The component data to set\n * @returns The component data that was set\n * @throws {@link ComponentNotRegistered} when the component class of the instance is not registered\n */\n private setEntity<T extends Component>(entityId: number, componentData: T): T {\n // get the component map\n const map = this.components.get((<ComponentClass<any>>componentData.constructor));\n if (map === undefined) throw new ComponentNotRegistered(componentData.constructor.name)\n\n // set the entity on the entity map\n map.set(entityId, componentData);\n\n // return instance\n return componentData;\n }\n\n /**\n * Add or update multiple component data for an entity\n * @param entityId - The entity id to set components for\n * @param component - A single component data instance to set\n * @param components - Multiple component data instances to set\n * @returns The single component data or an array of component data that were set\n * @throws {@link ComponentNotRegistered} when any of the component classes are not registered\n * @example\n * // set one\n * const player = ecs.set(entityId, new Player());\n * \n * // or set multiple\n * const [player, position] = ecs.set(\n * entityId,\n * new Player(),\n * new Position()\n * );\n */\n set<T extends Component>(entityId: number, component: T): T;\n set<T extends Component[]>(entityId: number, ...components: T): T;\n set(entityId: number, ...components: Component[]): Component | Component[] {\n if (components.length > 1) return components.map(x => this.setEntity(entityId, x))\n\n // set and return a single component\n return this.setEntity(entityId, components[0])\n }\n\n /**\n * Removes the specified component(s) from an entity\n * @param entityId - The entity id to remove components from\n * @param components - One or more component classes to remove\n * @throws {@link ComponentNotRegistered} when any of the specified component(s) are not registered\n * @example\n * ecs.remove(entityId, Position);\n */\n remove<T extends ComponentClass<any>[]>(entityId: number, ...components: T) {\n for (const component of components) {\n this.removeByKey(entityId, component)\n }\n }\n\n /**\n * Removes the specified component from an entity\n * @param entityId - The entity id to remove the component from\n * @param component - The component class to remove\n * @returns True if the component was successfully removed, otherwise false\n * @throws {@link ComponentNotRegistered} when the specified component is not registered\n * @example\n * ecs.removeByKey(entityId, Position);\n */\n removeByKey(entityId: number, component: ComponentClass<any>) {\n // get the entity map\n const entityMap = this.components.get(component);\n\n // ensure the map is defined\n if (entityMap === undefined) throw new ComponentNotRegistered(component.name);\n\n // get the entity\n const entity = entityMap.get(entityId);\n if (entity === undefined) return false;\n\n // remove the entity from the entity map\n return entityMap.delete(entityId);\n }\n\n /**\n * Deletes all components from an entity and reclaims the id for reuse\n * @param entityIds - One or more entity ids to destroy\n * @returns The total number of components destroyed\n * @example\n * const destroyedCount = ecs.destroyEntity(entityId1)\n * \n * // or multiple\n * const destroyedCount = ecs.destroyEntity(entityId1, entityId2)\n */\n destroyEntity(...entityIds: number[]): number {\n let deletedCount = 0;\n for (let index = 0; index < entityIds.length; index++) {\n const entityId = entityIds[index];\n let found = false;\n for (const map of this.components.values()) {\n if (map.has(entityId)) {\n map.delete(entityId);\n deletedCount++;\n found = true;\n }\n }\n if (found) {\n this.freeIds.push(entityId);\n }\n }\n return deletedCount;\n }\n\n /**\n * Creates a new entity id for the EntityMap.\n * \n * Reuses Ids from destroyed entities otherwise increments the Id counter.\n * @returns A new unique entity id\n * @example\n * const newEntityId = ecs.getNextId()\n * ecs.set(newEntityId, new Player())\n */\n getNextId(): number {\n const reclaimedId = this.freeIds.pop();\n if (reclaimedId !== undefined) return reclaimedId;\n\n this.nextId++;\n return this.nextId;\n }\n\n /**\n * Clears all registered component classes, all entity data and all reclaimed IDs\n * @returns The {@link EntityMap} instance for chaining\n * @example\n * ecs.clear()\n */\n clear() {\n this.components.clear();\n this.nextId = 0;\n this.freeIds.length = 0;\n return this;\n }\n\n /**\n * Clears all component data and reclaimed IDs while keeping the registered component classes\n * @returns The {@link EntityMap} instance for chaining\n * @example\n * ecs.clearComponents()\n */\n clearComponents() {\n this.components.forEach(x => x.clear())\n this.nextId = 0\n this.freeIds.length = 0;\n return this;\n }\n\n /**\n * Iterates over each entity that contains the specified key component\n * @param keyComponent - The primary component class used to filter entities\n * @param components - Additional component classes to retrieve for each entity\n * @returns A {@link ComponentIterator} that yields tuples of [entityId, keyComponentData, ...relatedComponentData]\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * // iterate each component data that is related to the Player entity\n * const iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) { }\n * \n * // you can also declare the type of iterator before it's assigned\n * // using the ComponentIterator type\n * let iterator: ComponentIterator<[Player, Position]>\n * \n * // then with late bound assignment (keeping the iterator intellisense)\n * iterator = ecs.iterator(Player, Position)\n * \n * for(const [playerId, player, position] of iterator) {\n * const moving = player.isMoving\n * }\n */\n iterator<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ) {\n return new ComponentIterator(new ComponentQuery(this, keyComponent, ...components));\n }\n\n /**\n * Creates a query that can be stored and reused\n * @param keyComponent - The primary component class used to filter entities\n * @param components - Additional component classes to retrieve for each entity\n * @returns A {@link ComponentQuery} instance\n * @throws {@link ComponentNotRegistered} when any of specified component(s) are not registered\n * @example\n * const query = ecs.query(Player, Position)\n * \n * // get the first entry\n * const [playerId, player, position] = query.firstEntry() ?? []\n * \n * // get the first key\n * const [playerId, position] = query.firstKey() ?? []\n * \n * // get the first value\n * const [player, position] = query.firstValue() ?? []\n * \n * // iterate\n * for (const [playerId, player, position] of query) {\n * \n * }\n */\n query<TKey, TRelated extends any[]>(\n keyComponent: ComponentClass<TKey>,\n ...components: ComponentClasses<TRelated>\n ) {\n return new ComponentQuery(this, keyComponent, ...components)\n }\n\n /**\n * Prints all component maps in a tabular format to the console.\n * \n * Additional generated columns are:\n * \n * 'Entity.Key' is the entity id\n * \n * 'Entity.Type' is the component name\n * \n * @param components - Optional filter. Only includes specific component class names.\n * @param properties - Optional filter. Specifies which property columns to display in the tables.\n * @returns The {@link EntityMap} instance for chaining\n */\n printTable(components?: string[]): this;\n printTable(components?: string[], properties?: string[]): this;\n printTable(components: string[] = [], properties: string[] = []) {\n this.components.forEach((map, key) => {\n if (components.length === 0 || components.includes(key)) {\n console.table(map.toTable(), properties);\n }\n });\n return this;\n }\n\n /**\n * Prints all component data for the specified entity id in a tabular format to the console\n * \n * Additional generated columns are:\n * \n * 'Entity.Type' is the component name\n * \n * @param entityId - The entity id to print\n * @param properties - Optional filter. Specifies which property columns to display in the tables.\n * @returns The {@link EntityMap} instance for chaining\n */\n printEntity(entityId: number, properties: string[] = []) {\n for (const map of this.components.values()) {\n if (map.has(entityId) === false) continue;\n\n const data = map.get(entityId);\n const columns = {\n 'entity.type': data.constructor.name,\n ...data\n };\n console.table({ [entityId]: columns }, properties);\n }\n\n return this;\n }\n\n /**\n * Parses the JSON and returns an {@link EntityMap} object\n * @param json - The JSON string representing an {@link EntityMap}\n * @returns A restored {@link EntityMap} instance\n * @example\n * const json = JSON.stringify(ecs);\n * const restoredMap = EntityMap.parse(json);\n */\n static parse(json: string): EntityMap {\n const restored = JSON.parse(json, function (key: string, value: any) {\n if (value.hasOwnProperty('components')) {\n Reflect.setPrototypeOf(value, EntityMap.prototype);\n return value;\n }\n if (value.hasOwnProperty('nextId')) return value;\n if (value.hasOwnProperty('freeIds')) return value;\n if (value.hasOwnProperty(ComponentMapKey)) return new ComponentMap(value.iterable);\n if (value.hasOwnProperty(ComponentClassesMapKey)) return new ComponentClassesMap(value.iterable);\n return this[key];\n });\n return restored;\n }\n\n /**\n * A tracing method used for debugging.\n * Intercepts all functions specified and logs each call to the console.\n * @param funcFilter - A list of function names you want to intercept. If no function names are specified then will log all functions called.\n * @returns A new proxy of an {@link EntityMap} with tracing enabled\n * @example\n * // trace all method calls\n * const ecs = EntityMap.createWithTracing();\n * \n * // trace only 'set' and 'remove' calls\n * const ecs = EntityMap.createWithTracing(['set', 'remove']);\n */\n static createWithTracing(funcFilter: string[] = []) {\n const traceHandler = {\n get(target: any, propKey: string) {\n const targetValue = target[propKey]\n\n if (typeof targetValue === 'function' && (funcFilter.length === 0 || funcFilter.includes(propKey))) {\n return function (this: any, ...args: any[]) {\n console.groupCollapsed('ecs trace', propKey, args);\n console.trace();\n console.groupEnd();\n return targetValue.apply(this, args);\n }\n }\n\n return targetValue;\n }\n }\n\n return new Proxy(new EntityMap(), traceHandler)\n }\n\n}", "/*\n ecsjs is an entity component system library for JavaScript\n Copyright (C) 2014 Peter Flannery\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU Affero General Public License as\n published by the Free Software Foundation, either version 3 of the\n License, or (at your option) any later version.\n\n This program is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Affero General Public License for more details.\n\n You should have received a copy of the GNU Affero General Public License\n along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\n/**\n * An entity component system library for JavaScript\n * @showCategories\n * @module ecsjs\n */\nimport { EntityMap } from './entity-map.js'\nexport { ComponentClassesMap } from './component-classes.js'\nexport { ComponentMap } from './component-map.js'\nexport { EntityMap } from './entity-map.js'\nexport type { ComponentNotRegistered, ComponentTypeKeyMissing } from './errors.js'\nexport { ComponentIterator } from './iterator.js'\nexport { ComponentQuery } from './query.js'\nexport type { ComponentClass, IComponentIterator } from './types.js'\n\n/**\n * A global default instance of an {@link EntityMap}\n * \n * Provides a convenient way to use the ECS without managing multiple maps.\n * \n * See the [cheat sheet](https://gitlab.com/ecsjs/ecs/-/blob/master/docs/cheat-sheet.md) for more examples.\n * @category Constants\n * @example\n * // register component(s)\n * ecs.register(Player, Position)\n * \n * // create an entity and set its components\n * const [player, position] = ecs.set(ecs.getNextId(), new Player(), new Position(10, 40))\n */\nexport const ecs = new EntityMap()\n\nif (typeof window !== 'undefined') {\n // @ts-ignore: exports to window\n window.ecs = ecs\n} else if (typeof module !== 'undefined' && module !== null) {\n // exports to nodejs\n module.exports = { ecs };\n}"],
5
+ "mappings": "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",
6
+ "names": ["ComponentMapKey", "ComponentClassesMapKey", "hashString", "str", "hash", "i", "char", "ComponentClassesMap", "entries", "i", "entry", "componentClass", "index", "map", "hashString", "hash", "existingIndex", "hashId", "lastIndex", "lastHash", "callback", "instances", "hashes", "value", "ComponentClassesMapKey", "ComponentMap", "entries", "i", "entry", "entityId", "component", "index", "lastIdx", "lastEntity", "callback", "entities", "instances", "result", "ComponentMapKey", "table", "key", "value", "entity", "meta", "properties", "ComponentTypeKeyMissing", "ComponentNotRegistered", "componentName", "ComponentIterator", "query", "entry", "value", "done", "entityId", "i", "map", "ComponentQuery", "ecs", "components", "i", "entityId", "entryValue", "results", "keyValue", "keyMap", "componentMaps", "keysIterator", "key", "value", "map", "ComponentIterator", "EntityMap", "_EntityMap", "ComponentClassesMap", "componentClasses", "componentClass", "ComponentTypeKeyMissing", "ComponentMap", "component", "map", "ComponentNotRegistered", "keyComponent", "entityId", "entities", "x", "components", "keyValue", "v", "index", "componentData", "entityMap", "entityIds", "deletedCount", "found", "reclaimedId", "ComponentIterator", "ComponentQuery", "properties", "key", "data", "columns", "json", "value", "ComponentMapKey", "ComponentClassesMapKey", "funcFilter", "traceHandler", "target", "propKey", "targetValue", "args", "ecs", "EntityMap"]
7
7
  }
@@ -4,7 +4,7 @@ import { ComponentIterator } from './iterator.js';
4
4
  import { ComponentQuery } from './query.js';
5
5
  import { type Component, type ComponentClass, type ComponentClasses, type SingleOrArray } from './types.js';
6
6
  /**
7
- * Class for storing entities and their relationships
7
+ * Class for storing entities and their relationships.
8
8
  * @category Maps
9
9
  */
10
10
  export declare class EntityMap {
@@ -13,6 +13,7 @@ export declare class EntityMap {
13
13
  */
14
14
  components: ComponentClassesMap;
15
15
  private nextId;
16
+ private freeIds;
16
17
  /**
17
18
  * Registers component classes with the {@link EntityMap}
18
19
  * @param componentClasses - One or more component classes to register
@@ -225,6 +226,7 @@ export declare class EntityMap {
225
226
  * Removes the specified component(s) from an entity
226
227
  * @param entityId - The entity id to remove components from
227
228
  * @param components - One or more component classes to remove
229
+ * @throws {@link ComponentNotRegistered} when any of the specified component(s) are not registered
228
230
  * @example
229
231
  * ecs.remove(entityId, Position);
230
232
  */
@@ -240,7 +242,7 @@ export declare class EntityMap {
240
242
  */
241
243
  removeByKey(entityId: number, component: ComponentClass<any>): boolean;
242
244
  /**
243
- * Deletes all components from an entity
245
+ * Deletes all components from an entity and reclaims the id for reuse
244
246
  * @param entityIds - One or more entity ids to destroy
245
247
  * @returns The total number of components destroyed
246
248
  * @example
@@ -251,7 +253,9 @@ export declare class EntityMap {
251
253
  */
252
254
  destroyEntity(...entityIds: number[]): number;
253
255
  /**
254
- * Creates a new entity id for the EntityMap
256
+ * Creates a new entity id for the EntityMap.
257
+ *
258
+ * Reuses Ids from destroyed entities otherwise increments the Id counter.
255
259
  * @returns A new unique entity id
256
260
  * @example
257
261
  * const newEntityId = ecs.getNextId()
@@ -259,13 +263,17 @@ export declare class EntityMap {
259
263
  */
260
264
  getNextId(): number;
261
265
  /**
262
- * Clears all registered component classes and all entity data
266
+ * Clears all registered component classes, all entity data and all reclaimed IDs
263
267
  * @returns The {@link EntityMap} instance for chaining
268
+ * @example
269
+ * ecs.clear()
264
270
  */
265
271
  clear(): this;
266
272
  /**
267
- * Clears all component data while keeping the registered component classes
273
+ * Clears all component data and reclaimed IDs while keeping the registered component classes
268
274
  * @returns The {@link EntityMap} instance for chaining
275
+ * @example
276
+ * ecs.clearComponents()
269
277
  */
270
278
  clearComponents(): this;
271
279
  /**
@@ -357,6 +365,12 @@ export declare class EntityMap {
357
365
  * Intercepts all functions specified and logs each call to the console.
358
366
  * @param funcFilter - A list of function names you want to intercept. If no function names are specified then will log all functions called.
359
367
  * @returns A new proxy of an {@link EntityMap} with tracing enabled
368
+ * @example
369
+ * // trace all method calls
370
+ * const ecs = EntityMap.createWithTracing();
371
+ *
372
+ * // trace only 'set' and 'remove' calls
373
+ * const ecs = EntityMap.createWithTracing(['set', 'remove']);
360
374
  */
361
375
  static createWithTracing(funcFilter?: string[]): any;
362
376
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entity-map.d.ts","sourceRoot":"","sources":["../../../src/entity-map.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"entity-map.d.ts","sourceRoot":"","sources":["../../../src/entity-map.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,SAAS;IACpB;;OAEG;IACI,UAAU,sBAA4B;IAE7C,OAAO,CAAC,MAAM,CAAY;IAE1B,OAAO,CAAC,OAAO,CAAe;IAE9B;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,iBAAiB,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,gBAAgB,EAAE,iBAAiB;IAchG;;;;;;;;;;OAUG;IACH,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAMpE;;;;;;;;;;OAUG;IACH,KAAK,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,SAAS,EAAE,GAAG,SAAS;IAEjE;;;;;;;;OAQG;IACH,WAAW,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,SAAS,EAAE,GAAG,SAAS;IAOvE;;;;;;;;OAQG;IACH,YAAY,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,SAAS;IAO/E;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE,EACrC,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC,EAClC,GAAG,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GACxC,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,SAAS;IAO1C;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE,EACnC,YAAY,EAAE,IAAI,EAClB,GAAG,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GACxC,aAAa,CAAC,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAYnD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,UAAU,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE,EACrC,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC,EAClC,GAAG,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GACxC,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAajD;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAOjB;;;;;;;;;;;;;;;OAeG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,SAAS;IAC9C,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS;IACrE,GAAG,CAAC,CAAC,SAAS,GAAG,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,SAAS;IAYxG;;;;;;;OAOG;IACH,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO;IAQ/D;;;;;;;OAOG;IACH,MAAM,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO;IAUpF;;;;;;;OAOG;IACH,MAAM,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC,GAAG,OAAO;IAUpF;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;IAYjB;;;;;;;;;;;;;;;;;OAiBG;IACH,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC;IAC3D,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC,GAAG,CAAC;IAQjE;;;;;;;OAOG;IACH,MAAM,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;IAM1E;;;;;;;;OAQG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,CAAC,GAAG,CAAC;IAe5D;;;;;;;;;OASG;IACH,aAAa,CAAC,GAAG,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM;IAmB7C;;;;;;;;OAQG;IACH,SAAS,IAAI,MAAM;IAQnB;;;;;OAKG;IACH,KAAK;IAOL;;;;;OAKG;IACH,eAAe;IAOf;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE,EACnC,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC,EAClC,GAAG,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC;IAK3C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE,EAChC,YAAY,EAAE,cAAc,CAAC,IAAI,CAAC,EAClC,GAAG,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CAAC;IAK3C;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IACvC,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAU9D;;;;;;;;;;OAUG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO;IAevD;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;IAerC;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,iBAAiB,CAAC,UAAU,GAAE,MAAM,EAAO;CAqBnD"}
@@ -61,6 +61,7 @@ export declare class ComponentQuery<TKey, TRelated extends any[]> {
61
61
  firstValue(): SingleOrArray<[TKey, ...TRelated]> | undefined;
62
62
  /**
63
63
  * Returns the count of entities matching the query
64
+ * @returns The number of entities that have the key component
64
65
  */
65
66
  get entityCount(): number;
66
67
  /**
@@ -80,12 +81,18 @@ export declare class ComponentQuery<TKey, TRelated extends any[]> {
80
81
  * Gets all component data matching the query.
81
82
  *
82
83
  * @returns An {@link Iterator} of `[keyComponentData, ...relatedComponentData]` tuples containing component data
84
+ * @example
85
+ * const query = ecs.query(Player, Position)
86
+ * for (const [player, position] of query.values()) { }
83
87
  */
84
88
  values(): Iterator<[TKey, ...TRelated]>;
85
89
  /**
86
90
  * Gets all component data entries matching the query
87
91
  *
88
92
  * @returns A {@link ComponentIterator} instance that yields `[entityId, keyComponentData, ...relatedComponentData]`
93
+ * @example
94
+ * const query = ecs.query(Player, Position)
95
+ * for (const [entityId, player, position] of query.entries()) { }
89
96
  */
90
97
  entries(): ComponentIterator<TKey, TRelated>;
91
98
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/query.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAc,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE;IAW7C,GAAG,EAAE,SAAS;IAVvB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAA0B;IAE/C;;;;;OAKG;gBAEM,GAAG,EAAE,SAAS,EACrB,GAAG,UAAU,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAQtE;;;;;OAKG;IACH,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,SAAS;IAerD;;;;;;;;OAQG;IACH,QAAQ,IAAI,aAAa,CAAC,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAc5D;;;;;;;;OAQG;IACH,UAAU,IAAI,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAe5D;;OAEG;IACH,IAAI,WAAW,WAEd;IAED;;;;;OAKG;IACH,eAAe,IAAI,MAAM;IAIzB;;;;OAIG;IACH,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC;IAE7B;;;;OAIG;IACH,MAAM,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;IA2BvC;;;;OAIG;IACH,OAAO;IAEP;;OAEG;IACH,CAAC,MAAM,CAAC,QAAQ,CAAC;CAIlB"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/query.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAc,CAAC,IAAI,EAAE,QAAQ,SAAS,GAAG,EAAE;IAW7C,GAAG,EAAE,SAAS;IAVvB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAA0B;IAE/C;;;;;OAKG;gBAEM,GAAG,EAAE,SAAS,EACrB,GAAG,UAAU,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAQtE;;;;;OAKG;IACH,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,SAAS;IAerD;;;;;;;;OAQG;IACH,QAAQ,IAAI,aAAa,CAAC,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAc5D;;;;;;;;OAQG;IACH,UAAU,IAAI,aAAa,CAAC,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS;IAe5D;;;OAGG;IACH,IAAI,WAAW,WAEd;IAED;;;;;OAKG;IACH,eAAe,IAAI,MAAM;IAIzB;;;;OAIG;IACH,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC;IAE7B;;;;;;;OAOG;IACH,MAAM,IAAI,QAAQ,CAAC,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;IA2BvC;;;;;;;OAOG;IACH,OAAO;IAEP;;OAEG;IACH,CAAC,MAAM,CAAC,QAAQ,CAAC;CAIlB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "title": "ECS JS",
3
3
  "name": "ecsjs",
4
- "version": "1.4.0-beta.4",
4
+ "version": "1.4.0-beta.5",
5
5
  "description": "An entity component system library for JavaScript",
6
6
  "author": "2013+ pflannery (https://gitlab.com/pflannery)",
7
7
  "license": "GNU GPL v3",
package/src/entity-map.ts CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  } from './types.js';
31
31
 
32
32
  /**
33
- * Class for storing entities and their relationships
33
+ * Class for storing entities and their relationships.
34
34
  * @category Maps
35
35
  */
36
36
  export class EntityMap {
@@ -41,6 +41,8 @@ export class EntityMap {
41
41
 
42
42
  private nextId: number = 0
43
43
 
44
+ private freeIds: number[] = []
45
+
44
46
  /**
45
47
  * Registers component classes with the {@link EntityMap}
46
48
  * @param componentClasses - One or more component classes to register
@@ -382,6 +384,7 @@ export class EntityMap {
382
384
  * Removes the specified component(s) from an entity
383
385
  * @param entityId - The entity id to remove components from
384
386
  * @param components - One or more component classes to remove
387
+ * @throws {@link ComponentNotRegistered} when any of the specified component(s) are not registered
385
388
  * @example
386
389
  * ecs.remove(entityId, Position);
387
390
  */
@@ -416,7 +419,7 @@ export class EntityMap {
416
419
  }
417
420
 
418
421
  /**
419
- * Deletes all components from an entity
422
+ * Deletes all components from an entity and reclaims the id for reuse
420
423
  * @param entityIds - One or more entity ids to destroy
421
424
  * @returns The total number of components destroyed
422
425
  * @example
@@ -429,46 +432,61 @@ export class EntityMap {
429
432
  let deletedCount = 0;
430
433
  for (let index = 0; index < entityIds.length; index++) {
431
434
  const entityId = entityIds[index];
435
+ let found = false;
432
436
  for (const map of this.components.values()) {
433
437
  if (map.has(entityId)) {
434
438
  map.delete(entityId);
435
439
  deletedCount++;
440
+ found = true;
436
441
  }
437
442
  }
443
+ if (found) {
444
+ this.freeIds.push(entityId);
445
+ }
438
446
  }
439
447
  return deletedCount;
440
448
  }
441
449
 
442
- // TODO create id generator
443
450
  /**
444
- * Creates a new entity id for the EntityMap
451
+ * Creates a new entity id for the EntityMap.
452
+ *
453
+ * Reuses Ids from destroyed entities otherwise increments the Id counter.
445
454
  * @returns A new unique entity id
446
455
  * @example
447
456
  * const newEntityId = ecs.getNextId()
448
457
  * ecs.set(newEntityId, new Player())
449
458
  */
450
459
  getNextId(): number {
460
+ const reclaimedId = this.freeIds.pop();
461
+ if (reclaimedId !== undefined) return reclaimedId;
462
+
451
463
  this.nextId++;
452
464
  return this.nextId;
453
465
  }
454
466
 
455
467
  /**
456
- * Clears all registered component classes and all entity data
468
+ * Clears all registered component classes, all entity data and all reclaimed IDs
457
469
  * @returns The {@link EntityMap} instance for chaining
470
+ * @example
471
+ * ecs.clear()
458
472
  */
459
473
  clear() {
460
474
  this.components.clear();
461
- this.nextId = 0
475
+ this.nextId = 0;
476
+ this.freeIds.length = 0;
462
477
  return this;
463
478
  }
464
479
 
465
480
  /**
466
- * Clears all component data while keeping the registered component classes
481
+ * Clears all component data and reclaimed IDs while keeping the registered component classes
467
482
  * @returns The {@link EntityMap} instance for chaining
483
+ * @example
484
+ * ecs.clearComponents()
468
485
  */
469
486
  clearComponents() {
470
487
  this.components.forEach(x => x.clear())
471
488
  this.nextId = 0
489
+ this.freeIds.length = 0;
472
490
  return this;
473
491
  }
474
492
 
@@ -596,6 +614,8 @@ export class EntityMap {
596
614
  Reflect.setPrototypeOf(value, EntityMap.prototype);
597
615
  return value;
598
616
  }
617
+ if (value.hasOwnProperty('nextId')) return value;
618
+ if (value.hasOwnProperty('freeIds')) return value;
599
619
  if (value.hasOwnProperty(ComponentMapKey)) return new ComponentMap(value.iterable);
600
620
  if (value.hasOwnProperty(ComponentClassesMapKey)) return new ComponentClassesMap(value.iterable);
601
621
  return this[key];
@@ -608,6 +628,12 @@ export class EntityMap {
608
628
  * Intercepts all functions specified and logs each call to the console.
609
629
  * @param funcFilter - A list of function names you want to intercept. If no function names are specified then will log all functions called.
610
630
  * @returns A new proxy of an {@link EntityMap} with tracing enabled
631
+ * @example
632
+ * // trace all method calls
633
+ * const ecs = EntityMap.createWithTracing();
634
+ *
635
+ * // trace only 'set' and 'remove' calls
636
+ * const ecs = EntityMap.createWithTracing(['set', 'remove']);
611
637
  */
612
638
  static createWithTracing(funcFilter: string[] = []) {
613
639
  const traceHandler = {
package/src/query.ts CHANGED
@@ -130,6 +130,7 @@ export class ComponentQuery<TKey, TRelated extends any[]> {
130
130
 
131
131
  /**
132
132
  * Returns the count of entities matching the query
133
+ * @returns The number of entities that have the key component
133
134
  */
134
135
  get entityCount() {
135
136
  return this.keyMap.size
@@ -156,6 +157,9 @@ export class ComponentQuery<TKey, TRelated extends any[]> {
156
157
  * Gets all component data matching the query.
157
158
  *
158
159
  * @returns An {@link Iterator} of `[keyComponentData, ...relatedComponentData]` tuples containing component data
160
+ * @example
161
+ * const query = ecs.query(Player, Position)
162
+ * for (const [player, position] of query.values()) { }
159
163
  */
160
164
  values(): Iterator<[TKey, ...TRelated]> {
161
165
  const keyMap = this.keyMap;
@@ -188,6 +192,9 @@ export class ComponentQuery<TKey, TRelated extends any[]> {
188
192
  * Gets all component data entries matching the query
189
193
  *
190
194
  * @returns A {@link ComponentIterator} instance that yields `[entityId, keyComponentData, ...relatedComponentData]`
195
+ * @example
196
+ * const query = ecs.query(Player, Position)
197
+ * for (const [entityId, player, position] of query.entries()) { }
191
198
  */
192
199
  entries() { return this[Symbol.iterator](); }
193
200