@arancini/core
Advanced tools
Comparing version 3.3.0 to 4.0.0
@@ -8,54 +8,12 @@ /** | ||
words: Uint32Array; | ||
/** | ||
* Constructor for a new BitSet | ||
* @param indices initial indices for the BitSet | ||
*/ | ||
constructor(indices?: Iterable<number>); | ||
/** | ||
* Adds a given index to the BitSet | ||
* @param index the index to add | ||
*/ | ||
add(index: number): void; | ||
/** | ||
* Removes a given index from the BitSet | ||
* @param index the index to remove | ||
*/ | ||
remove(index: number): void; | ||
/** | ||
* Returns whether the given index is set | ||
* @param index the index | ||
* @returns whether the given index is set | ||
*/ | ||
add(...indices: number[]): void; | ||
remove(...indices: number[]): void; | ||
has(index: number): boolean; | ||
/** | ||
* Resizes the bitset | ||
* @param index the max index | ||
*/ | ||
resize(index: number): void; | ||
/** | ||
* Clears all words in the BitSet | ||
*/ | ||
reset(): void; | ||
/** | ||
* Copies the contents of another BitSet into this BitSet | ||
* @param bitset the other BitSet | ||
*/ | ||
copy(bitset: BitSet): void; | ||
/** | ||
* Creates a clone of this BitSet | ||
* @returns a clone of this BitSet | ||
*/ | ||
clone(): BitSet; | ||
/** | ||
* Returns whether this BitSet contains all indices in another BitSet | ||
* @param other the other BitSet | ||
* @returns whether this BitSet contains all indices in another BitSet | ||
*/ | ||
containsAll(other: BitSet): boolean; | ||
/** | ||
* Returns whether this BitSet contains any indices in another BitSet | ||
* @param other the other BitSet | ||
* @returns whether this BitSet contains any indices in another BitSet | ||
*/ | ||
containsAny(other: BitSet): boolean; | ||
} |
@@ -1,13 +0,13 @@ | ||
import { QueryDescription } from '.'; | ||
import { Entity } from './entity'; | ||
import { Topic } from './topic'; | ||
export declare class EntityContainer { | ||
import type { AnyEntity } from './world'; | ||
export declare class EntityContainer<Entity> { | ||
entities: Entity[]; | ||
version: number; | ||
entities: Entity[]; | ||
onEntityAdded: Topic<[Entity]>; | ||
onEntityRemoved: Topic<[Entity]>; | ||
private entityPositions; | ||
/** @ignore */ | ||
_entityPositions: Map<Entity, number>; | ||
/** @ignore */ | ||
_entitySet: Set<Entity>; | ||
get first(): Entity | undefined; | ||
filter(queryDescription: QueryDescription): Entity[]; | ||
find(queryDescription: QueryDescription): Entity | undefined; | ||
[Symbol.iterator](): { | ||
@@ -20,10 +20,4 @@ next: () => { | ||
has(entity: Entity): boolean; | ||
/** | ||
* @ignore internal | ||
*/ | ||
_addEntity(entity: Entity): void; | ||
/** | ||
* @ignore internal | ||
*/ | ||
_removeEntity(entity: Entity): void; | ||
} | ||
export declare const addEntityToContainer: <E extends AnyEntity>(container: EntityContainer<E>, entity: E) => void; | ||
export declare const removeEntityFromContainer: <E extends AnyEntity>(container: EntityContainer<E>, entity: E) => void; |
@@ -1,8 +0,5 @@ | ||
export * from './component'; | ||
export * from './entity'; | ||
export { ObjectPool } from './pools'; | ||
export { Query } from './query'; | ||
export { type QueryBuilderFn, type QueryConditions, type QueryDescription, } from './query-utils'; | ||
export * from './system'; | ||
export * from './object-pool'; | ||
export { Query, QueryBuilder, type QueryConditions, type QueryDescription, type With, type Without, } from './query'; | ||
export { System, type SystemClass } from './system'; | ||
export * from './topic'; | ||
export * from './world'; | ||
export { World, type WorldOptions, type AnyEntity } from './world'; |
@@ -1,2 +0,2 @@ | ||
const t={CLASS:1,OBJECT:2,TAG:3};class e{construct(...t){}onInit(){}onDestroy(){}static componentIndex;static type=t.CLASS;static objectPooled=!1;entity;_arancini_id;_arancini_component_definition;static object({name:e}){return{name:e,type:t.OBJECT,componentIndex:-1,T:void 0}}static tag({name:e}){return{name:e,type:t.TAG,componentIndex:-1,T:void 0}}}const s=e=>{if(e.type===t.CLASS){const t=class extends e{};return t.componentIndex=-1,t}const s={...e};return s.componentIndex=-1,s};let n=0;const i=()=>(n++,n.toString());class o{words;constructor(t=[]){this.words=new Uint32Array(8);for(const e of t)this.add(e)}add(t){this.resize(t),this.words[t>>>5]|=1<<t}remove(t){this.resize(t),this.words[t>>>5]&=~(1<<t)}has(t){return 0!=(this.words[t>>>5]&1<<t)}resize(t){if(this.words.length<<5>t)return;const e=new Uint32Array(t+32>>>5<<1);e.set(this.words),this.words=e}reset(){for(let t=0;t<this.words.length;t++)this.words[t]=0}copy(t){const e=new Uint32Array(t.words.length);e.set(t.words),this.words=e}clone(){const t=new Uint32Array(this.words.length);t.set(this.words);const e=new o;return e.words=t,e}containsAll(t){for(let e=0;e<this.words.length;e++)if(0!=(~this.words[e]&t.words[e]))return!1;return!0}containsAny(t){for(let e=0;e<this.words.length;e++)if(0!=(this.words[e]&t.words[e]))return!0;return!1}}class r{id=i();initialised=!1;world;_componentsBitSet=new o;_components={};_updateQueries=!0;_updateBitSet=!0;add(e,...s){if(this._components[e.componentIndex])throw new Error(`Cannot add component ${e.name}, entity with id ${this.id} already has this component`);let n;e.type===t.CLASS?(n=e.objectPooled?this.world.componentPool.request(e):new e,n.construct(...s)):n=e.type===t.OBJECT?s[0]:{};const o=n;return o._arancini_id=i(),o._arancini_component_definition=e,this._components[e.componentIndex]=n,this._componentsBitSet.add(e.componentIndex),e.type===t.CLASS&&(n.entity=this,this.initialised&&n.onInit()),this._updateQueries&&this.world.queryManager.onEntityComponentChange(this),n}remove(e){const s=this.find(e);if(void 0===s)throw new Error("Component does not exist in Entity");const n=s,{componentIndex:o}=n._arancini_component_definition;if(delete this._components[o],this._updateBitSet&&this._componentsBitSet.remove(o),n._arancini_component_definition.type===t.CLASS){const t=s;t.onDestroy(),t.entity=void 0,n._arancini_component_definition.objectPooled&&(n._arancini_id=i(),this.world.componentPool.recycle(s))}else delete n._arancini_component_definition,delete n._arancini_id;return this._updateQueries&&this.world.queryManager.onEntityComponentChange(this),this}bulk(t){return this._updateQueries=!1,t(this),this._updateQueries=!0,this.world.queryManager.onEntityComponentChange(this),this}get(t){const e=this._components[t.componentIndex];if(!e)throw new Error(`Component ${t}} with componentIndex ${t.componentIndex} not in entity ${this.id} - ${Object.keys(this._components)}`);return e}getAll(){return Object.values(this._components)}find(t){return this._components[t.componentIndex]}has(t){return!!this._components[t.componentIndex]}destroy(){this.world?.destroy(this)}}class a{availableObjects=[];factory;get available(){return this.availableObjects.length}get used(){return this.size-this.availableObjects.length}size=0;constructor(t,e){this.factory=t,void 0!==e&&this.grow(e)}grow(t){for(let e=0;e<t;e++)this.availableObjects.push(this.factory());this.size+=t}free(t){for(let e=0;e<t;e++){if(!this.availableObjects.pop())break;this.size--}}request(){return this.availableObjects.length<=0&&this.grow(Math.round(.2*this.size)+1),this.availableObjects.pop()}recycle(t){this.availableObjects.push(t)}}class h{objectPool=new a((()=>{const t=new r;return t.world=this.world,t}));get size(){return this.objectPool.size}get available(){return this.objectPool.available}get used(){return this.objectPool.used}world;constructor(t){this.world=t}request(){return this.objectPool.request()}recycle(t){t.id=i(),t.initialised=!1,t._componentsBitSet.reset(),this.objectPool.recycle(t)}grow(t){this.objectPool.grow(t)}free(t){this.objectPool.free(t)}}class c{get totalPools(){return this.objectPools.size}get size(){let t=0;for(const e of this.objectPools.values())t+=e.size;return t}get available(){let t=0;for(const e of this.objectPools.values())t+=e.available;return t}get used(){let t=0;for(const e of this.objectPools.values())t+=e.used;return t}objectPools=new Map;request(t){return this.getPool(t).request()}recycle(t){this.objectPools.get(t._arancini_component_definition.componentIndex)?.recycle(t)}grow(t,e){this.getPool(t).grow(e)}free(t,e){this.getPool(t).free(e)}getPool(t){let e=this.objectPools.get(t.componentIndex);return void 0===e&&(e=new a((()=>new t)),this.objectPools.set(t.componentIndex,e)),e}}const l=t=>t.map((({type:t,components:e})=>"all"===t?e.map((t=>`${t.componentIndex}`)).sort().join(","):[`${t}:${e.map((t=>t.componentIndex)).sort().join(",")}`])).sort().join("&"),d=t=>{let e;if("function"==typeof t){const s=new p;t(s),e=s.conditions}else e=t.every((t=>"componentIndex"in t))?[{type:"all",components:t}]:t;if(e.length<=0)throw new Error("Query must have at least one condition");if(e.some((t=>t.components.length<=0)))throw new Error("Query conditions must have at least one component");const s={type:"all",components:[]},n=[];for(const t of e)"all"===t.type?s.components.push(...t.components):n.push(t);return[s,...n]},u=t=>t.map((t=>({[t.type]:new o(t.components.map((t=>t.componentIndex)))}))),y=(t,e)=>{for(const s of t){if(s.all&&!e._componentsBitSet.containsAll(s.all))return!1;if(s.any&&!e._componentsBitSet.containsAny(s.any))return!1;if(s.not&&e._componentsBitSet.containsAny(s.not))return!1}return!0},m=(t,e)=>{const s=[];for(const n of e)y(t,n)&&s.push(n);return s};class p{conditions=[];constructor(){}all=(...t)=>(this.conditions.push({type:"all",components:t}),this);any=(...t)=>(this.conditions.push({type:"any",components:t}),this);not=(...t)=>(this.conditions.push({type:"not",components:t}),this);with=this.all;have=this.all;has=this.all;every=this.all;some=this.any;one=this.any;withAny=this.any;none=this.not;without=this.not;get and(){return this}get but(){return this}get where(){return this}get that(){return this}get are(){return this}get also(){return this}}class _{listeners=new Set;add(t){return this.listeners.add(t),()=>this.remove(t)}remove(t){this.listeners.delete(t)}emit(...t){for(const e of this.listeners)e(...t)}clear(){this.listeners.clear()}}class w{version=0;entities=[];onEntityAdded=new _;onEntityRemoved=new _;entityPositions=new Map;get first(){return this.entities[0]||void 0}filter(t){const e=d(t),s=u(e);return m(s,this.entities)}find(t){const e=d(t);return((t,e)=>{for(const s of e)if(y(t,s))return s})(u(e),this.entities)}[Symbol.iterator](){let t=this.entities.length;const e={value:void 0,done:!1};return{next:()=>(e.value=this.entities[--t],e.done=t<0,e)}}has(t){return this.entityPositions.has(t)}_addEntity(t){t&&!this.has(t)&&(this.entities.push(t),this.entityPositions.set(t,this.entities.length-1),this.version++,this.onEntityAdded.emit(t))}_removeEntity(t){if(!this.has(t))return;const e=this.entityPositions.get(t);this.entityPositions.delete(t);const s=this.entities[this.entities.length-1];s!==t&&(this.entities[e]=s,this.entityPositions.set(s,e)),this.entities.pop(),this.version++,this.onEntityRemoved.emit(t)}}class f extends w{world;key;conditions;bitSets;constructor(t,e,s,n){super(),this.world=t,this.key=e,this.conditions=s,this.bitSets=n}destroy(){this.world.queryManager.removeQuery(this)}}class g{queries=new Map;queryOwners=new Map;world;constructor(t){this.world=t}createQuery(t,e="standalone"){const s=d(t),n=l(s);let i=this.queries.get(n);if(void 0===i){i=new f(this.world,n,s,u(s));const t=m(i.bitSets,this.world.entities.values());for(const e of t)i._addEntity(e);this.queries.set(n,i)}if(e){const t=this.queryOwners.get(n)??[];t.push(e),this.queryOwners.set(n,t)}return i}removeQuery(t,e="standalone"){if(!this.queries.has(t.key))return;let s=this.queryOwners.get(t.key)??[];s=s.filter((t=>t!==e)),s.length>0?this.queryOwners.set(t.key,s):(this.queries.delete(t.key),this.queryOwners.delete(t.key),t.onEntityAdded.clear(),t.onEntityRemoved.clear())}findQuery(t){const e=d(t),s=l(e);return this.queries.get(s)}onEntityComponentChange(t){for(const e of this.queries.values()){const s=y(e.bitSets,t),n=e.has(t);s&&!n?e._addEntity(t):!s&&n&&e._removeEntity(t)}}}class S{enabled=!0;world;__internal={class:null,queries:new Set,priority:0,order:0,requiredQueries:[],hasRequiredQueries:!1};constructor(t){this.world=t}onDestroy(){}onInit(){}onUpdate(t,e){}unregister(){this.world.unregisterSystem(this.__internal.class)}query(t,e){return this.world.systemManager.createSystemQuery(this,t,e)}singleton(t,e){return{__internal:{systemSingletonPlaceholder:!0,componentDefinition:t,options:e}}}attach(t){return{__internal:{attachedSystemPlaceholder:!0,systemClass:t}}}}class v{systems=new Map;sortedSystems=[];systemCounter=0;systemAttachments=new Map;world;constructor(t){this.world=t}init(){for(const t of this.systems.values())this.initSystem(t);this.sortSystems()}destroy(){for(const t of this.systems.values())t.onDestroy()}registerSystem(t,e){if(this.systems.has(t))throw new Error(`System "${t.name}" has already been registered`);this.systemCounter++;const s=new t(this.world);this.systems.set(t,s),s.__internal.class=t,s.__internal.priority=e?.priority??0,s.__internal.order=this.systemCounter,this.initSingletonQueries(s),this.updateAllSystemAttachments();const n=(i=t,o="onUpdate",Object.getOwnPropertyNames(i.prototype).includes(o));var i,o;n&&this.sortedSystems.push(s),this.world.initialised&&(this.initSystem(s),n&&this.sortSystems())}unregisterSystem(t){const e=this.systems.get(t);e&&(this.systems.delete(t),this.sortedSystems=this.sortedSystems.filter((e=>e.__internal.class!==t)),e.__internal.queries.forEach((t=>{this.world.queryManager.removeQuery(t,e)})),e.__internal.requiredQueries=[],e.onDestroy(),this.updateAllSystemAttachments())}createSystemQuery(t,e,s){const n=this.world.queryManager.createQuery(e,t);return t.__internal.queries.add(n),s?.required&&(t.__internal.requiredQueries.push(n),t.__internal.hasRequiredQueries=!0),n}initSystem(t){t.onInit()}initSingletonQueries(t){for(const e in t){const s=t,n=s[e];if(n?.__internal?.systemSingletonPlaceholder){const{__internal:{componentDefinition:i,options:o}}=n,r=this.createSystemQuery(t,[i],o),a=()=>{s[e]=r.first?.get(i)};r.onEntityAdded.add(a),r.onEntityRemoved.add(a),a()}}}updateSystemAttachments(t){for(const e in t){const s=t[e];if(s?.__internal?.attachedSystemPlaceholder){const n=this.systemAttachments.get(t)??[];n.push({field:e,systemClass:s.__internal.systemClass}),this.systemAttachments.set(t,n);const{__internal:{systemClass:i}}=s;t[e]=this.world.getSystem(i)}}const e=this.systemAttachments.get(t)??[];for(const{field:s,systemClass:n}of e)t[s]=this.world.getSystem(n)}updateAllSystemAttachments(){for(const t of this.systems.values())this.updateSystemAttachments(t)}sortSystems(){this.sortedSystems.sort(((t,e)=>e.__internal.priority-t.__internal.priority||t.__internal.order-e.__internal.order))}}class b{components=new Map;currentComponentIndex=-1;world;constructor(t){this.world=t}registerComponent(t){let e=this.components.get(t);if(void 0!==e)return e;if(this.currentComponentIndex++,e=this.currentComponentIndex,t.componentIndex=e,this.components.set(t,e),this.world.initialised)for(const t of this.world.entities.values())t._componentsBitSet.resize(this.currentComponentIndex);return e}}class q extends w{initialised=!1;time=0;queryManager;systemManager;componentRegistry;componentPool;entityPool;constructor(){super(),this.componentRegistry=new b(this),this.queryManager=new g(this),this.systemManager=new v(this),this.componentPool=new c,this.entityPool=new h(this)}init(){this.initialised=!0;for(const t of this.entities)this.initialiseEntity(t);this.systemManager.init()}update(t=0){this.time+=t;for(const e of this.systemManager.sortedSystems.values())e.enabled&&(e.__internal.hasRequiredQueries&&e.__internal.requiredQueries.some((t=>0===t.entities.length))||e.onUpdate(t,this.time))}reset(){this.time=0,this.initialised=!1,this.systemManager.destroy();for(const t of this.entities.values())this.destroy(t)}create(t){const e=this.entityPool.request();return this.initialised&&this.initialiseEntity(e),t&&e.bulk(t),this._addEntity(e),e}destroy(t){this._removeEntity(t),t._updateQueries=!1,t._updateBitSet=!1;for(const e of Object.values(t._components)){const s=e;t.remove(s._arancini_component_definition)}t._updateQueries=!0,t._updateBitSet=!0;for(const e of this.queryManager.queries.values())e._removeEntity(t);this.entityPool.recycle(t)}query(t){return this.queryManager.createQuery(t)}filter(t){const e=this.queryManager.findQuery(t);return e?e.entities:super.filter(t)}find(t){const e=this.queryManager.findQuery(t);return e?e.first:super.find(t)}registerComponent(t){return this.componentRegistry.registerComponent(t),this}registerSystem(t,e){return this.systemManager.registerSystem(t,e),this}unregisterSystem(t){return this.systemManager.unregisterSystem(t),this}getSystem(t){return this.systemManager.systems.get(t)}getSystems(){return Array.from(this.systemManager.systems.values())}initialiseEntity(e){e.initialised=!0;for(const s of Object.values(e._components)){const e=s;e._arancini_component_definition?.type===t.CLASS&&s.onInit()}}}export{e as Component,t as ComponentDefinitionType,r as Entity,a as ObjectPool,f as Query,S as System,v as SystemManager,_ as Topic,q as World,s as cloneComponentDefinition}; | ||
class t{availableObjects=[];factory;get available(){return this.availableObjects.length}get used(){return this.size-this.availableObjects.length}size=0;constructor(t,e){this.factory=t,void 0!==e&&this.grow(e)}grow(t){for(let e=0;e<t;e++)this.availableObjects.push(this.factory());this.size+=t}free(t){for(let e=0;e<t;e++){if(!this.availableObjects.pop())break;this.size--}}request(){return this.availableObjects.length<=0&&this.grow(Math.round(.2*this.size)+1),this.availableObjects.pop()}recycle(t){this.availableObjects.push(t),this.availableObjects.length>Math.round(.2*this.size)&&this.free(this.availableObjects.length-Math.round(.2*this.size))}}class e{words;constructor(t=[]){this.words=new Uint32Array(8);for(const e of t)this.add(e)}add(...t){for(let e=0;e<t.length;e++){const s=t[e];this.resize(s),this.words[s>>>5]|=1<<s}}remove(...t){for(let e=0;e<t.length;e++){const s=t[e];this.resize(s),this.words[s>>>5]&=~(1<<s)}}has(t){return 0!=(this.words[t>>>5]&1<<t)}resize(t){if(this.words.length<<5>t)return;const e=new Uint32Array(t+32>>>5<<1);e.set(this.words),this.words=e}reset(){for(let t=0;t<this.words.length;t++)this.words[t]=0}copy(t){const e=new Uint32Array(t.words.length);e.set(t.words),this.words=e}clone(){const t=new Uint32Array(this.words.length);t.set(this.words);const s=new e;return s.words=t,s}containsAll(t){for(let e=0;e<this.words.length;e++)if(0!=(~this.words[e]&t.words[e]))return!1;return!0}containsAny(t){for(let e=0;e<this.words.length;e++)if(0!=(this.words[e]&t.words[e]))return!0;return!1}}class s{listeners=new Set;add(t){return this.listeners.add(t),()=>this.remove(t)}remove(t){this.listeners.delete(t)}emit(...t){for(const e of this.listeners)e(...t)}clear(){this.listeners.clear()}}class i{entities=[];version=0;onEntityAdded=new s;onEntityRemoved=new s;_entityPositions=new Map;_entitySet=new Set;get first(){return this.entities[0]||void 0}[Symbol.iterator](){let t=this.entities.length;const e={value:void 0,done:!1};return{next:()=>(e.value=this.entities[--t],e.done=t<0,e)}}has(t){return this._entitySet.has(t)}}const n=(t,e)=>{e&&!t.has(e)&&(t.entities.push(e),t._entityPositions.set(e,t.entities.length-1),t._entitySet.add(e),t.version++,t.onEntityAdded.emit(e))},r=(t,e)=>{if(!t.has(e))return;const s=t._entityPositions.get(e);t._entityPositions.delete(e),t._entitySet.delete(e);const i=t.entities[t.entities.length-1];i!==e&&(t.entities[s]=i,t._entityPositions.set(i,s)),t.entities.pop(),t.version++,t.onEntityRemoved.emit(e)},o=new t((()=>({bitset:new e,id:void 0}))),h=Symbol("__arancini");class a extends i{world;key;conditions;bitSets;constructor(t,e,s,i){super(),this.world=t,this.key=e,this.conditions=s,this.bitSets=i}destroy(){this.world.destroyQuery(this)}}const l=(t,e)=>{const s=[];for(const i of e)d(t,i)&&s.push(i);return s},d=(t,e)=>{const s=e;for(const e of t){if("all"===e.type&&!s[h].bitset.containsAll(e.bitset))return!1;if("any"===e.type&&!s[h].bitset.containsAny(e.bitset))return!1;if("not"===e.type&&s[h].bitset.containsAny(e.bitset))return!1}return!0},y=t=>{const e=new m;t(e);const s=e.conditions;if(s.length<=0)throw new Error("Query must have at least one condition");if(s.some((t=>t.components.length<=0)))throw new Error("Query conditions must have at least one component");const i={type:"all",components:[]},n=[];for(const t of s)"all"===t.type?i.components.push(...t.components):n.push(t);return[i,...n]},c=(t,e)=>e.map((({type:e,components:s})=>"all"===e?s.map((e=>t[e])).sort().join(","):[`${e}:${s.map((e=>t[e])).sort().join(",")}`])).sort().join("&"),u=(t,s)=>s.map((s=>({type:s.type,bitset:new e(s.components.map((e=>t[e])))})));class m{T;conditions=[];all=(...t)=>(this.conditions.push({type:"all",components:t}),this);any=(...t)=>(this.conditions.push({type:"any",components:t}),this);not=(...t)=>(this.conditions.push({type:"not",components:t}),this);with=this.all;have=this.all;has=this.all;every=this.all;is=this.all;some=this.any;one=this.any;none=this.not;without=this.not;get and(){return this}get but(){return this}get where(){return this}get are(){return this}}class p{enabled=!0;world;__internal={class:null,queries:new Set,priority:0,order:0,requiredQueries:[]};constructor(t){this.world=t}onDestroy(){}onInit(){}onUpdate(t,e){}unregister(){this.world.unregisterSystem(this.__internal.class)}query(t,e){return this.world.systemManager.createSystemQuery(this,t,e)}singleton(t,e){return{__internal:{systemSingletonPlaceholder:!0,component:t,options:e}}}attach(t){return{__internal:{attachedSystemPlaceholder:!0,systemClass:t}}}}class g{systems=new Map;sortedSystems=[];systemCounter=0;systemAttachments=new Map;world;constructor(t){this.world=t}init(){for(const t of this.systems.values())this.initSystem(t);this.sortSystems()}update(t,e){for(let s=0;s<this.sortedSystems.length;s++){const i=this.sortedSystems[s];i.enabled&&(i.__internal.requiredQueries.length>0&&i.__internal.requiredQueries.some((t=>0===t.entities.length))||i.onUpdate(t,e))}}destroy(){for(const t of this.systems.values())t.onDestroy()}registerSystem(t,e){if(this.systems.has(t))throw new Error(`System "${t.name}" has already been registered`);this.systemCounter++;const s=new t(this.world);this.systems.set(t,s),s.__internal.class=t,s.__internal.priority=e?.priority??0,s.__internal.order=this.systemCounter,this.initSingletonQueries(s),this.updateAllSystemAttachments();const i=(n=t,r="onUpdate",Object.getOwnPropertyNames(n.prototype).includes(r));var n,r;i&&this.sortedSystems.push(s),this.world.initialised&&(this.initSystem(s),i&&this.sortSystems())}unregisterSystem(t){const e=this.systems.get(t);e&&(this.systems.delete(t),this.sortedSystems=this.sortedSystems.filter((e=>e.__internal.class!==t)),e.__internal.queries.forEach((t=>{this.world.destroyQuery(t,e)})),e.__internal.requiredQueries=[],e.onDestroy(),this.updateAllSystemAttachments())}createSystemQuery(t,e,s){const i=this.world.query(e,{owner:t});return s?.required&&t.__internal.requiredQueries.push(i),i}initSystem(t){t.onInit()}initSingletonQueries(t){for(const e in t){const s=t,i=s[e];if(i?.__internal?.systemSingletonPlaceholder){const{__internal:{component:n,options:r}}=i,o=t=>t.has(n),h=this.createSystemQuery(t,o,r),a=()=>{s[e]=h.first?.[n]};h.onEntityAdded.add(a),h.onEntityRemoved.add(a),a()}}}updateSystemAttachments(t){for(const e in t){const s=t[e];if(s?.__internal?.attachedSystemPlaceholder){const i=this.systemAttachments.get(t)??[];i.push({field:e,systemClass:s.__internal.systemClass}),this.systemAttachments.set(t,i);const{__internal:{systemClass:n}}=s;t[e]=this.world.getSystem(n)}}const e=this.systemAttachments.get(t)??[];for(const{field:s,systemClass:i}of e)t[s]=this.world.getSystem(i)}updateAllSystemAttachments(){for(const t of this.systems.values())this.updateSystemAttachments(t)}sortSystems(){this.sortedSystems.sort(((t,e)=>e.__internal.priority-t.__internal.priority||t.__internal.order-e.__internal.order))}}class f extends i{time=0;initialised=!1;systemManager;queries=new Map;queryConsumers=new Map;componentIndexCounter=-1;componentRegistry={};idToEntity=new Map;entityIdCounter=0;bulkUpdateInProgress=!1;bulkUpdateEntities=new Set;constructor(t){super(),this.systemManager=new g(this),t?.components&&this.registerComponents(t.components)}init(){this.initialised=!0,this.systemManager.init()}step(t){this.time+=t,this.systemManager.update(t,this.time)}reset(){this.time=0,this.initialised=!1,this.systemManager.destroy(),this.entities.forEach((t=>this.destroy(t))),this.entityIdCounter=0,this.idToEntity.clear(),this._entityPositions.clear()}id(t){if(!this.has(t))return;const e=t;let s=e[h].id;return void 0===s&&(s=this.entityIdCounter++,this.idToEntity.set(s,t),e[h].id=s),s}entity(t){return this.idToEntity.get(t)}create(t){n(this,t);const e=t;return e[h]=o.request(),e[h].bitset.add(...Object.keys(t).map((t=>this.componentRegistry[t]))),this.index(t),t}destroy(t){r(this,t);const e=t;e[h].bitset.reset(),this.index(t),this.queries.forEach((e=>r(e,t)));let s=e[h].id;s&&this.idToEntity.delete(s),e[h].bitset.reset(),e[h].id=void 0,o.recycle(e[h]),delete e[h]}add(t,e,s){if(void 0!==t[e])return this;t[e]=s;return t[h].bitset.add(this.componentRegistry[e]),this.index(t),this}remove(t,e){if(void 0!==t[e]){if(this.has(t)){t[h].bitset.remove(this.componentRegistry[e]),this.index(t)}delete t[e]}}update(t,e){if("function"==typeof e){const s=e,i=new Proxy(t,{set:(e,s,i)=>{const n=s,r=n in t;return r&&void 0===i?this.remove(t,n):r?Reflect.set(t,s,i):this.add(t,n,i),!0},deleteProperty:(e,s)=>(this.remove(t,s),!0)});this.bulk((()=>{s(i)}))}else{const s=e;this.bulk((()=>{for(const e in s){const i=s[e];void 0!==i?this.add(t,e,i):this.remove(t,e)}}))}}bulk(t){this.bulkUpdateInProgress=!0,t(),this.bulkUpdateInProgress=!1;for(const t of this.bulkUpdateEntities)this.index(t);this.bulkUpdateEntities.clear()}query(t,e){const s=y(t),i=c(this.componentRegistry,s);let r=this.queries.get(i);if(r)return r;r=new a(this,i,s,u(this.componentRegistry,s));const o=l(r.bitSets,this.entities.values());for(const t of o)n(r,t);this.queries.set(i,r);const h=e?.owner??"standalone",d=this.queryConsumers.get(r.key)??[];return d.push(h),this.queryConsumers.set(r.key,d),r}destroyQuery(t,e="standalone"){if(!this.queries.has(t.key))return;let s=this.queryConsumers.get(t.key)??[];s=s.filter((t=>t!==e)),s.length>0?this.queryConsumers.set(t.key,s):(this.queries.delete(t.key),this.queryConsumers.delete(t.key),t.onEntityAdded.clear(),t.onEntityRemoved.clear())}filter(t){const e=y(t),s=c(this.componentRegistry,e),i=this.queries.get(s);if(i)return i.entities;const n=u(this.componentRegistry,e);return l(n,this.entities)}find(t){const e=y(t),s=c(this.componentRegistry,e),i=this.queries.get(s);if(i)return i.first;return((t,e)=>{for(const s of e)if(d(t,s))return s})(u(this.componentRegistry,e),this.entities)}registerComponents(t){for(const e of t)this.registerComponent(e);if(this.initialised)for(const t of this.entities.values()){t[h].bitset.resize(this.componentIndexCounter)}}registerSystem(t,e){return this.systemManager.registerSystem(t,e),this}unregisterSystem(t){return this.systemManager.unregisterSystem(t),this}getSystem(t){return this.systemManager.systems.get(t)}getSystems(){return Array.from(this.systemManager.systems.values())}index(t){if(this.has(t))if(this.bulkUpdateInProgress)this.bulkUpdateEntities.add(t);else for(const e of this.queries.values()){const s=d(e.bitSets,t),i=e.has(t);s&&!i?n(e,t):!s&&i&&r(e,t)}}registerComponent(t){let e=this.componentRegistry[t];return void 0===e&&(this.componentIndexCounter++,e=this.componentIndexCounter,this.componentRegistry[t]=e),e}}export{t as ObjectPool,a as Query,m as QueryBuilder,p as System,s as Topic,f as World}; | ||
//# sourceMappingURL=index.es.js.map |
@@ -1,69 +0,53 @@ | ||
import type { Entity } from './entity'; | ||
import { BitSet } from './bit-set'; | ||
import { EntityContainer } from './entity-container'; | ||
import { QueryBitSets, QueryConditions, QueryDescription } from './query-utils'; | ||
import type { World } from './world'; | ||
/** | ||
* A Query for Entities with specified Components. | ||
* | ||
* Queries can contain a minimum of one and a maximum of three conditions, the `entities`, `one`, and `not` QueryConditionType conditions. | ||
* | ||
* Queries can either be created as part of Systems, or they can be created standalone. | ||
* | ||
* Changes to Entity Components are queued, and Query results are updated as part of the World update loop. | ||
* | ||
* Query results can also be retrieved once-off without creating a persistent query with `world.find(...)`. | ||
* | ||
* ```ts | ||
* import { Component, System, World } from '@arancini/core' | ||
* | ||
* // create a world | ||
* const world = new World() | ||
* | ||
* // create some example components | ||
* class ExampleComponentOne extends Component {} | ||
* class ExampleComponentTwo extends Component {} | ||
* | ||
* // get once-off query results, re-using existing query results if available | ||
* world.filter((q) => q.all(ExampleComponentOne, ExampleComponentTwo)) | ||
* | ||
* // get a query that will update reactively | ||
* const query = world.query((q) => q.all(ExampleComponentOne, ExampleComponentTwo)) | ||
* | ||
* // create a system with a query | ||
* class ExampleSystem extends System { | ||
* exampleQueryName = this.query((q) => q.all(ExampleComponentOne, ExampleComponentTwo)) | ||
* | ||
* onUpdate() { | ||
* this.exampleQueryName.entities.forEach((entity) => console.log(entity)) | ||
* } | ||
* } | ||
* | ||
* world.registerSystem(ExampleSystem) | ||
* ``` | ||
*/ | ||
export declare class Query extends EntityContainer { | ||
import type { ComponentRegistry, World } from './world'; | ||
export type With<E, P extends keyof E> = E & Required<Pick<E, P>>; | ||
export type Without<E, P extends keyof E> = Pick<E, Exclude<keyof E, P>> & Partial<Pick<E, P>>; | ||
export type QueryConditionType = 'all' | 'any' | 'not'; | ||
export type QueryCondition<E> = { | ||
type: QueryConditionType; | ||
components: (keyof E)[]; | ||
}; | ||
export type QueryConditions<E> = QueryCondition<E>[]; | ||
export type QueryBitSets = { | ||
type: QueryConditionType; | ||
bitset: BitSet; | ||
}[]; | ||
export type QueryDescription<E, R> = (q: QueryBuilder<E>) => QueryBuilder<R>; | ||
export declare class Query<E> extends EntityContainer<E> { | ||
world: World; | ||
key: string; | ||
conditions: QueryConditions; | ||
conditions: QueryConditions<E>; | ||
bitSets: QueryBitSets; | ||
constructor(world: World, key: string, conditions: QueryConditions, bitSets: QueryBitSets); | ||
/** | ||
* Destroys the Query | ||
*/ | ||
constructor(world: World, key: string, conditions: QueryConditions<E>, bitSets: QueryBitSets); | ||
destroy(): void; | ||
} | ||
/** | ||
* QueryManager is an internal class that manages Query instances | ||
* | ||
* @private internal class, do not use directly | ||
*/ | ||
export declare class QueryManager { | ||
queries: Map<string, Query>; | ||
queryOwners: Map<string, unknown[]>; | ||
private world; | ||
constructor(world: World); | ||
createQuery(queryDescription: QueryDescription, owner?: unknown): Query; | ||
removeQuery(query: Query, owner?: unknown): void; | ||
findQuery(queryDescription: QueryDescription): Query | undefined; | ||
onEntityComponentChange(entity: Entity): void; | ||
export declare const getQueryResults: <E>(queryBitSets: QueryBitSets, entities: Iterable<E>) => E[]; | ||
export declare const getFirstQueryResult: <E>(queryBitSets: QueryBitSets, entities: Iterable<E>) => E | undefined; | ||
export declare const evaluateQueryBitSets: <E>(queryBitSets: QueryBitSets, entity: E) => boolean; | ||
export declare const getQueryConditions: (queryDescription: QueryDescription<any, any>) => QueryConditions<any>; | ||
export declare const getQueryDedupeString: (componentRegistry: ComponentRegistry, queryConditions: QueryConditions<unknown>) => string; | ||
export declare const getQueryBitSets: (componentRegistry: ComponentRegistry, conditions: QueryConditions<any>) => { | ||
type: QueryConditionType; | ||
bitset: BitSet; | ||
}[]; | ||
export declare class QueryBuilder<E> { | ||
T: E; | ||
conditions: QueryConditions<E>; | ||
all: <C extends keyof E>(...components: C[]) => QueryBuilder<With<E, C>>; | ||
any: <C extends keyof E>(...components: C[]) => QueryBuilder<E>; | ||
not: <C extends keyof E>(...components: C[]) => QueryBuilder<Without<E, C>>; | ||
with: <C extends keyof E>(...components: C[]) => QueryBuilder<With<E, C>>; | ||
have: <C extends keyof E>(...components: C[]) => QueryBuilder<With<E, C>>; | ||
has: <C extends keyof E>(...components: C[]) => QueryBuilder<With<E, C>>; | ||
every: <C extends keyof E>(...components: C[]) => QueryBuilder<With<E, C>>; | ||
is: <C extends keyof E>(...components: C[]) => QueryBuilder<With<E, C>>; | ||
some: <C extends keyof E>(...components: C[]) => QueryBuilder<E>; | ||
one: <C extends keyof E>(...components: C[]) => QueryBuilder<E>; | ||
none: <C extends keyof E>(...components: C[]) => QueryBuilder<Without<E, C>>; | ||
without: <C extends keyof E>(...components: C[]) => QueryBuilder<Without<E, C>>; | ||
get and(): this; | ||
get but(): this; | ||
get where(): this; | ||
get are(): this; | ||
} |
@@ -1,4 +0,2 @@ | ||
import { ComponentDefinition, ComponentInstance } from './component'; | ||
import type { QueryDescription } from './query-utils'; | ||
import { Query } from './query'; | ||
import type { Query, QueryDescription } from './query'; | ||
import type { World } from './world'; | ||
@@ -46,3 +44,3 @@ export type SystemQueryOptions = { | ||
*/ | ||
export declare abstract class System { | ||
export declare abstract class System<E extends {} = any> { | ||
/** | ||
@@ -55,3 +53,3 @@ * Whether the system is enabled and should update | ||
*/ | ||
world: World; | ||
world: World<E>; | ||
/** | ||
@@ -68,3 +66,3 @@ * @private used internally, do not use directly | ||
*/ | ||
queries: Set<Query>; | ||
queries: Set<Query<E>>; | ||
/** | ||
@@ -81,7 +79,3 @@ * The priority of the system, determines system run order. | ||
*/ | ||
requiredQueries: Query[]; | ||
/** | ||
* Whether the system has any required queries | ||
*/ | ||
hasRequiredQueries: boolean; | ||
requiredQueries: Query<any>[]; | ||
}; | ||
@@ -113,3 +107,3 @@ constructor(world: World); | ||
*/ | ||
protected query(queryDescription: QueryDescription, options?: SystemQueryOptions): Query; | ||
protected query<ResultEntity>(queryDescription: QueryDescription<E, ResultEntity>, options?: SystemQueryOptions): Query<ResultEntity>; | ||
/** | ||
@@ -119,3 +113,3 @@ * Shortcut for creating a query for a singleton component. | ||
*/ | ||
protected singleton<T extends ComponentDefinition<unknown>>(componentDefinition: T, options?: SystemQueryOptions): ComponentInstance<T> | undefined; | ||
protected singleton<C extends keyof E>(component: C, options?: SystemQueryOptions): E[C] | undefined; | ||
/** | ||
@@ -135,7 +129,4 @@ * Returns a reference to another system that updates as systems are registered and unregistered. | ||
export declare class SystemManager { | ||
/** | ||
* Systems in the System Manager | ||
*/ | ||
systems: Map<SystemClass, System>; | ||
sortedSystems: System[]; | ||
private sortedSystems; | ||
private systemCounter; | ||
@@ -145,27 +136,8 @@ private systemAttachments; | ||
constructor(world: World); | ||
/** | ||
* Initialises the system manager | ||
*/ | ||
init(): void; | ||
/** | ||
* Destroys all systems | ||
*/ | ||
update(delta: number, time: number): void; | ||
destroy(): void; | ||
/** | ||
* Adds a system to the system manager | ||
* @param Clazz the system class to add | ||
*/ | ||
registerSystem(Clazz: SystemClass, attributes?: SystemAttributes): void; | ||
/** | ||
* Unregisters a System from the SystemManager | ||
* @param clazz the System to remove | ||
*/ | ||
unregisterSystem(clazz: SystemClass): void; | ||
/** | ||
* Creates a query for a system | ||
* @param system the system to create the query for | ||
* @param queryDescription the query to create | ||
* @param options the options for the query | ||
*/ | ||
createSystemQuery(system: System, queryDescription: QueryDescription, options?: SystemQueryOptions): Query; | ||
createSystemQuery<E extends {}, ResultEntity>(system: System<E>, queryDescription: QueryDescription<E, ResultEntity>, options?: SystemQueryOptions): Query<ResultEntity>; | ||
private initSystem; | ||
@@ -172,0 +144,0 @@ private initSingletonQueries; |
@@ -1,120 +0,170 @@ | ||
import { type ComponentDefinition } from './component'; | ||
import { ComponentRegistry } from './component-registry'; | ||
import type { Entity } from './entity'; | ||
import { EntityContainer } from './entity-container'; | ||
import { ComponentPool, EntityPool } from './pools'; | ||
import type { Query } from './query'; | ||
import type { QueryDescription } from './query-utils'; | ||
import { QueryManager } from './query'; | ||
import type { System, SystemAttributes, SystemClass } from './system'; | ||
import { SystemManager } from './system'; | ||
/** | ||
* A World that can contain Entities, Systems, and Queries. | ||
* | ||
* ```ts | ||
* import { World } from '@arancini/core' | ||
* | ||
* const world = new World() | ||
* | ||
* // initialise the world | ||
* world.init() | ||
* | ||
* // update the world without specifying time elapsed | ||
* // (Systems will be called with a delta of 0) | ||
* world.update() | ||
* | ||
* // update the world with a specified time elapsed | ||
* // (Systems will be called with a delta of 0.1) | ||
* world.update(0.1) | ||
* | ||
* // reset the world, removing all entities | ||
* world.reset() | ||
* ``` | ||
*/ | ||
export declare class World extends EntityContainer { | ||
/** | ||
* Whether the World has been initialised | ||
*/ | ||
import { Query, QueryDescription } from './query'; | ||
import { System, SystemAttributes, SystemClass, SystemManager } from './system'; | ||
export type ComponentRegistry = { | ||
[name: string]: number; | ||
}; | ||
export type WorldOptions<E extends {}> = { | ||
components?: (keyof E)[]; | ||
}; | ||
export type AnyEntity = Record<string, any>; | ||
export declare class World<E extends AnyEntity = any> extends EntityContainer<E> { | ||
time: number; | ||
initialised: boolean; | ||
systemManager: SystemManager; | ||
queries: Map<string, Query<any>>; | ||
private queryConsumers; | ||
private componentIndexCounter; | ||
private componentRegistry; | ||
private idToEntity; | ||
private entityIdCounter; | ||
private bulkUpdateInProgress; | ||
private bulkUpdateEntities; | ||
constructor(options?: WorldOptions<E>); | ||
/** | ||
* The current World time | ||
* Initialises the World | ||
*/ | ||
time: number; | ||
init(): void; | ||
/** | ||
* The QueryManager for the World | ||
* Manages and updates Queries | ||
* Steps the world | ||
* @param delta the time elapsed since the last step | ||
*/ | ||
queryManager: QueryManager; | ||
step(delta: number): void; | ||
/** | ||
* The SystemManager for the World | ||
* Manages System lifecycles | ||
* Resets the world. Removes all entities, and calls onDestroy on all systems. | ||
* Components and Systems remain registered. | ||
* The world must be initialised again after this. | ||
*/ | ||
systemManager: SystemManager; | ||
reset(): void; | ||
/** | ||
* The ComponentRegistry for the World | ||
* Maintains a mapping of Component classes to Component indices | ||
* Creates and returns an id for an entity | ||
*/ | ||
componentRegistry: ComponentRegistry; | ||
id(entity: E): number | undefined; | ||
/** | ||
* Object pool for components | ||
* Returns an entity for an id | ||
* @param id | ||
* @returns | ||
*/ | ||
componentPool: ComponentPool; | ||
entity(id: number): E | undefined; | ||
/** | ||
* Object pool for entities | ||
* Creates a new entity | ||
* @param entity | ||
* @returns a proxied entity that | ||
* | ||
* | ||
* @example | ||
* ```ts | ||
* const entity = world.create({ | ||
* position: { x: 0, y: 0 }, | ||
* velocity: { x: 0, y: 0 }, | ||
* }) | ||
* ``` | ||
*/ | ||
entityPool: EntityPool; | ||
create(entity: E): E; | ||
/** | ||
* Constructor for a World | ||
* Destroys an entity | ||
* @param entity | ||
* | ||
* @example | ||
* ```ts | ||
* const entity = world.create({ foo: 'bar' }) | ||
* world.destroy(entity) | ||
* ``` | ||
*/ | ||
constructor(); | ||
destroy(entity: E): void; | ||
/** | ||
* Initialises the World | ||
* Adds a component to an entity | ||
* @param entity | ||
* @param component | ||
* @param value | ||
* @returns the world, for chaining | ||
* | ||
* @example | ||
* ```ts | ||
* const entity = {} | ||
* world.create(entity) | ||
* world.add(entity, 'foo', 'bar') | ||
* ``` | ||
*/ | ||
init(): void; | ||
add<C extends keyof E>(entity: E, component: C, value: E[C]): this; | ||
/** | ||
* Updates the World | ||
* @param delta the time elapsed in seconds, uses 0 if not specified | ||
* Removes a component from an entity | ||
* @param entity | ||
* @param component | ||
* @returns the world, for chaining | ||
* | ||
* @example | ||
* ```ts | ||
* const entity = {} | ||
* world.create(entity) | ||
* world.add(entity, 'foo', 'bar') | ||
* world.remove(entity, 'foo') | ||
* ``` | ||
*/ | ||
update(delta?: number): void; | ||
remove(entity: E, component: keyof E): void; | ||
/** | ||
* Resets the World. | ||
* Applies an update to an entity, checking for added and removed components and updating queries. | ||
* The update is applied in bulk, so queries are only updated once. | ||
* @param entity the entity to update | ||
* @param updateFn the update function | ||
* | ||
* This removes all entities, and calls onDestroy on all Systems. | ||
* Components and Systems will remain registered. | ||
* The World will need to be initialised again after this. | ||
* @example | ||
* ```ts | ||
* const entity = world.create({ health: 10, poisioned: true }) | ||
* | ||
* // add and remove components in a single bulk update, using regular object syntax | ||
* world.update(entity, (e) => { | ||
* // add a component | ||
* e.position = { x: 0, y: 0 } | ||
* | ||
* // remove a component | ||
* delete e.poisioned | ||
* }) | ||
* ``` | ||
*/ | ||
reset(): void; | ||
update(entity: E, updateFnOrPartial: ((entity: E) => void) | Partial<E>): void; | ||
/** | ||
* Creates an Entity | ||
* @param initFn an optional function to bulk add components to the new Entity | ||
* @returns the new Entity | ||
* Utility method for adding and removing components from entities in bulk. | ||
* @param updateFn callback to update entities in the World | ||
* | ||
* @example | ||
* ```ts | ||
* import { World } from '@arancini/core' | ||
* const entity = world.create({ health: 10, poisioned: true }) | ||
* | ||
* const world = new World() | ||
* | ||
* // create an entity | ||
* const entity = world.create() | ||
* | ||
* // create an entity with components | ||
* const entityWithComponents = world.create((entity) => { | ||
* entity.add(ExampleComponentOne) | ||
* entity.add(ExampleComponentTwo) | ||
* world.bulk(() => { | ||
* world.add(entity, 'position', { x: 0, y: 0 }) | ||
* world.remove(entity, 'poisioned') | ||
* }) | ||
* ``` | ||
*/ | ||
create(initFn?: (entity: Entity) => void): Entity; | ||
bulk(updateFn: () => void): void; | ||
/** | ||
* Destroys an Entity | ||
* @param entity the Entity to destroy | ||
* Creates a query that updates with entity composition changes. | ||
* @param queryDescription the query description | ||
* @returns the query | ||
* | ||
* @example | ||
* ```ts | ||
* const query = world.query((e) => e.has('position').and.has('velocity')) | ||
* ``` | ||
* | ||
* @example | ||
* ```ts | ||
* const query = world.query((e) => e.has('position').but.not('dead')) | ||
* ``` | ||
* | ||
* @example | ||
* ```ts | ||
* const query = world.query((e) => e.has('position').and.one('player', 'enemy')) | ||
* ``` | ||
*/ | ||
destroy(entity: Entity): void; | ||
query<ResultEntity extends E>(queryDescription: QueryDescription<E, ResultEntity>, options?: { | ||
owner: unknown; | ||
}): Query<ResultEntity>; | ||
/** | ||
* Creates a Query | ||
* @param queryDescription the query to create | ||
* @returns the Query | ||
* Destroys a Query | ||
* @param query the Query to remove | ||
* @returns | ||
*/ | ||
query(queryDescription: QueryDescription): Query; | ||
destroyQuery(query: Query<any>, owner?: unknown): void; | ||
/** | ||
@@ -125,3 +175,3 @@ * Filters entities that match a given query description. | ||
*/ | ||
filter(queryDescription: QueryDescription): Entity[]; | ||
filter<ResultEntity>(queryDescription: QueryDescription<E, ResultEntity>): ResultEntity[]; | ||
/** | ||
@@ -132,10 +182,8 @@ * Finds an entity that matches a given query description. | ||
*/ | ||
find(queryDescription: QueryDescription): Entity | undefined; | ||
find<ResultEntity>(queryDescription: QueryDescription<E, ResultEntity>): ResultEntity | undefined; | ||
/** | ||
* Registers a Component. | ||
* For best performance, register all Component classes before initialising the World. | ||
* @param componentDefinition the Component definition to register | ||
* @returns the World | ||
* Register components with the World | ||
* @param names | ||
*/ | ||
registerComponent(componentDefinition: ComponentDefinition<unknown>): World; | ||
registerComponents(components: (keyof E)[]): void; | ||
/** | ||
@@ -146,3 +194,3 @@ * Adds a system to the World | ||
*/ | ||
registerSystem<T extends System>(system: SystemClass<T>, attributes?: SystemAttributes): World; | ||
registerSystem(system: SystemClass, attributes?: SystemAttributes): World; | ||
/** | ||
@@ -153,3 +201,3 @@ * Removes a System from the World | ||
*/ | ||
unregisterSystem<T extends System>(system: SystemClass<T>): World; | ||
unregisterSystem(system: SystemClass): World; | ||
/** | ||
@@ -160,3 +208,3 @@ * Retrives a System by class | ||
*/ | ||
getSystem<S extends System>(clazz: SystemClass<S>): S | undefined; | ||
getSystem<S extends System<E>>(clazz: SystemClass<S>): S | undefined; | ||
/** | ||
@@ -166,4 +214,5 @@ * Retrieves a list of all Systems in the world | ||
*/ | ||
getSystems(): System[]; | ||
private initialiseEntity; | ||
getSystems(): System<E>[]; | ||
private index; | ||
private registerComponent; | ||
} |
@@ -12,3 +12,3 @@ { | ||
"license": "MIT", | ||
"version": "3.3.0", | ||
"version": "4.0.0", | ||
"homepage": "https://github.com/isaac-mason/arancini", | ||
@@ -44,3 +44,3 @@ "bugs": { | ||
"@typescript-eslint/parser": "^6.2.0", | ||
"@vitest/coverage-v8": "^0.34.4", | ||
"@vitest/coverage-v8": "^0.34.6", | ||
"eslint": "^8.48.0", | ||
@@ -62,3 +62,3 @@ "eslint-config-airbnb": "^19.0.4", | ||
"rollup": "^3.26.3", | ||
"rollup-plugin-copy": "^3.4.0", | ||
"rollup-plugin-copy": "^3.5.0", | ||
"rollup-plugin-filesize": "^10.0.0", | ||
@@ -65,0 +65,0 @@ "storybook": "^7.5.1", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
82640
14
580
1