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 +10 -0
- package/dist/ecs.js +1 -1
- package/dist/ecs.js.map +3 -3
- package/dist/types/src/entity-map.d.ts +19 -5
- package/dist/types/src/entity-map.d.ts.map +1 -1
- package/dist/types/src/query.d.ts +7 -0
- package/dist/types/src/query.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/entity-map.ts +33 -7
- package/src/query.ts +7 -0
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
|
|
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": "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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", "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
|
|
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":"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"}
|
|
@@ -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
|
|
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
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
|
|
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
|
|