New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@arancini/core

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@arancini/core - npm Package Compare versions

Comparing version 3.2.0 to 3.3.0

dist/bit-set.d.ts

55

dist/component.d.ts

@@ -44,34 +44,21 @@ import { Entity } from './entity';

} ? Args : never : never : T['type'] extends typeof ComponentDefinitionType.OBJECT ? [T['T']] : T['type'] extends typeof ComponentDefinitionType.TAG ? [] : never;
export type ObjectComponentDefinitionParams = {
/**
* The name of the component
*/
name?: string;
};
export type TagComponentDefinitionParams = {
/**
* The name of the component
*/
name?: string;
};
/**
* Decorator for opting ia class component into being object objectPooled.
*
* @example defining an object pooled component using the @objectPool decorator
* ```ts
* import { Component, objectPooled, World } from '@arancini/core'
*
* @objectPooled()
* class ExampleComponent extends Component {}
* ```
*
* This can also be achieved by setting the `objectPooled` property on a component class
* @example vanilla js
* ```js
* import { Component } from '@arancini/core'
*
* class ExampleComponent extends Component {}
* ExampleComponent.objectPooled = true
* ```
*/
export declare const objectPooled: () => (target: {
new (): Component;
objectPooled: boolean;
}, _v?: any) => void;
/**
* The base class for class components.
*
* * @example defining and creating a class component that extends the `Component` class and uses the `@objectPooled` decorator
* * @example defining and creating a class component that extends the `Component` class, and is opted into object pooling
* ```ts
* import { Component, objectPooled, World } from '@arancini/core'
* import { Component, World } from '@arancini/core'
*
* @objectPooled()
* class ExampleComponent extends Component {

@@ -99,2 +86,5 @@ * // When using typescript, the `!:` not null assertion can be used as a "late-init" syntax.

* }
*
* // opt-in to object pooling
* static objectPooled = true
* }

@@ -134,3 +124,3 @@ *

*
* @param name a name for the component
* @param param0 the object component definition parameters
* @return object component definition

@@ -142,3 +132,3 @@ *

*
* const PositionComponent = Component.object<{ x: number, y: number }>('Position')
* const PositionComponent = Component.object<{ x: number, y: number }>({ name: 'Position' })
*

@@ -153,6 +143,7 @@ * const world = new World()

*/
static object<T>(name: string): ObjectComponentDefinition<T>;
static object<T>({ name }: ObjectComponentDefinitionParams): ObjectComponentDefinition<T>;
/**
* Creates a tag component definition.
* @param name an name for the component
*
* @param param0 the tag component definition parameters
* @returns tag component definition

@@ -174,4 +165,4 @@ *

*/
static tag(name: string): TagComponentDefinition;
static tag({ name }: TagComponentDefinitionParams): TagComponentDefinition;
}
export declare const cloneComponentDefinition: <T extends ComponentDefinition<unknown>>(componentDefinition: T) => T;

@@ -0,1 +1,2 @@

import { QueryDescription } from '.';
import { Entity } from './entity';

@@ -10,2 +11,4 @@ import { Topic } from './topic';

get first(): Entity | undefined;
filter(queryDescription: QueryDescription): Entity[];
find(queryDescription: QueryDescription): Entity | undefined;
[Symbol.iterator](): {

@@ -12,0 +15,0 @@ next: () => {

import { type ComponentDefinition, type ComponentDefinitionArgs, type ComponentInstance } from './component';
import { BitSet } from './utils/bit-set';
import { BitSet } from './bit-set';
import type { World } from './world';

@@ -15,3 +15,3 @@ /**

* // example tag component without any data or behavior
* const TagComponent = Component.tag('TagComponent')
* const TagComponent = Component.tag({ name: 'TagComponent' })
*

@@ -18,0 +18,0 @@ * // create a world and register the component

export * from './component';
export * from './entity';
export { ObjectPool } from './pools';
export * from './query';
export { Query } from './query';
export { type QueryBuilderFn, type QueryConditions, type QueryDescription, } from './query-utils';
export * from './system';
export * from './topic';
export * from './world';

@@ -1,2 +0,2 @@

const t={CLASS:1,OBJECT:2,TAG:3},e=()=>(t,e)=>{t.objectPooled=!0};class s{construct(...t){}onInit(){}onDestroy(){}static componentIndex;static type=t.CLASS;static objectPooled=!1;entity;_arancini_id;_arancini_component_definition;static object(e){return{name:e,type:t.OBJECT,componentIndex:-1,T:void 0}}static tag(e){return{name:e,type:t.TAG,componentIndex:-1,T:void 0}}}const n=e=>{if(e.type===t.CLASS){const t=class extends e{};return t.componentIndex=-1,t}const s={...e};return s.componentIndex=-1,s};class i{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 i;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}}let o=0;const r=()=>(o++,o.toString());class a{id=r();initialised=!1;world;_componentsBitSet=new i;_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 i=n;return i._arancini_id=r(),i._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:i}=n._arancini_component_definition;if(delete this._components[i],this._updateBitSet&&this._componentsBitSet.remove(i),n._arancini_component_definition.type===t.CLASS){const t=s;t.onDestroy(),t.entity=void 0,n._arancini_component_definition.objectPooled&&(n._arancini_id=r(),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 h{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 l{objectPool=new h((()=>{const t=new a;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=r(),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 h((()=>new t)),this.objectPools.set(t.componentIndex,e)),e}}class d{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 y{version=0;entities=[];onEntityAdded=new d;onEntityRemoved=new d;entityPositions=new Map;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.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 u extends y{world;key;description;bitSets;constructor(t,e,s,n){super(),this.world=t,this.key=e,this.description=s,this.bitSets=n}destroy(){this.world.queryManager.removeQuery(this)}}const m=t=>Array.isArray(t)?t.map((t=>`${t.componentIndex}`)).join("&"):Object.entries(t).flatMap((([t,e])=>"all"===t?e.map((t=>`${t.componentIndex}`)).sort():[`${t}:${e.sort().map((t=>t.componentIndex))}`])).sort().join("&");class p{queries=new Map;queryOwners=new Map;world;constructor(t){this.world=t}createQuery(t,e="standalone"){const s=m(t);let n=this.queries.get(s);if(void 0===n){const e=Array.isArray(t);if(e&&0===t.length||!e&&(!t.all&&!t.any&&!t.not||t.all&&0===t.all.length||t.any&&0===t.any.length||t.not&&0===t.not.length))throw new Error("Query must have at least one condition");n=new u(this.world,s,t,this.getQueryBitSets(t));const i=this.getQueryResults(n.bitSets);for(const t of i)n._addEntity(t);this.queries.set(s,n)}if(e){const t=this.queryOwners.get(s)??[];t.push(e),this.queryOwners.set(s,t)}return n}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())}hasQuery(t){const e=m(t);return this.queries.has(e)}onEntityComponentChange(t){for(const e of this.queries.values()){const s=this.matchesQueryConditions(e.bitSets,t),n=e.has(t);s&&!n?e._addEntity(t):!s&&n&&e._removeEntity(t)}}onEntityRemoved(t){for(const e of this.queries.values())e._removeEntity(t)}find(t){const e=m(t),s=this.queries.get(e);return s?s.entities:this.getQueryResults(this.getQueryBitSets(t))}matchesQueryConditions(t,e){return!(t.all&&!e._componentsBitSet.containsAll(t.all))&&(!(t.any&&!e._componentsBitSet.containsAny(t.any))&&(!t.not||!e._componentsBitSet.containsAny(t.not)))}getQueryResults(t){const e=[];for(const s of this.world.entities.values())this.matchesQueryConditions(t,s)&&e.push(s);return e}getQueryBitSets(t){const{all:e,any:s,not:n}=Array.isArray(t)?{all:t,any:void 0,not:void 0}:t,o={};return o.all=e?new i(e.map((t=>t.componentIndex))):void 0,o.any=s?new i(s.map((t=>t.componentIndex))):void 0,o.not=n?new i(n.map((t=>t.componentIndex))):void 0,o}}class _{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,componentDefinition:t,options:e}}}attach(t){return{__internal:{attachedSystemPlaceholder:!0,systemClass:t}}}}class w{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(const s of this.sortedSystems.values())s.enabled&&(s.__internal.requiredQueries.length>0&&s.__internal.requiredQueries.some((t=>0===t.entities.length))||s.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 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),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 g{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 f extends y{initialised=!1;time=0;queryManager;systemManager;componentRegistry;componentPool;entityPool;constructor(){super(),this.componentRegistry=new g(this),this.queryManager=new p(this),this.systemManager=new w(this),this.componentPool=new c,this.entityPool=new l(this)}init(){this.initialised=!0;for(const t of this.entities)this.initialiseEntity(t);this.systemManager.init()}update(t=0){this.time+=t,this.systemManager.update(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,this.queryManager.onEntityRemoved(t),this.entityPool.recycle(t)}query(t){return this.queryManager.createQuery(t)}find(t){return this.queryManager.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{s as Component,t as ComponentDefinitionType,a as Entity,h as ObjectPool,u as Query,p as QueryManager,_ as System,w as SystemManager,d as Topic,f as World,n as cloneComponentDefinition,m as getQueryDedupeString,e as objectPooled};
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};
//# sourceMappingURL=index.es.js.map

@@ -1,21 +0,6 @@

import type { ComponentDefinition } from './component';
import type { Entity } from './entity';
import { EntityContainer } from './entity-container';
import { BitSet } from './utils/bit-set';
import { QueryBitSets, QueryConditions, QueryDescription } from './query-utils';
import type { World } from './world';
export type QueryConditionType = 'all' | 'any' | 'not';
/**
* Type for query conditions
*/
export type QueryDescription = ComponentDefinition<unknown>[] | {
all?: ComponentDefinition<unknown>[];
not?: ComponentDefinition<unknown>[];
any?: ComponentDefinition<unknown>[];
};
export type QueryBitSets = {
all?: BitSet;
any?: BitSet;
not?: BitSet;
};
/**
* A Query for Entities with specified Components.

@@ -32,3 +17,3 @@ *

* ```ts
* import { Component, System, World, QueryDescription } from '@arancini/core'
* import { Component, System, World } from '@arancini/core'
*

@@ -41,28 +26,12 @@ * // create a world

* class ExampleComponentTwo extends Component {}
* class ExampleComponentThree extends Component {}
* class ExampleComponentFour extends Component {}
*
* // create a simple query description
* const simpleQueryDescription: QueryDescription = [ExampleComponentOne, ExampleComponentTwo]
*
* // create a complex query description
* const queryDescription: QueryDescription = {
* all: [ExampleComponentOne],
* any: [ExampleComponentOne, ExampleComponentTwo],
* not: [ExampleComponentFour],
* }
*
* // get once-off query results, re-using existing query results if available
* world.find(simpleQueryDescription)
* world.filter((q) => q.all(ExampleComponentOne, ExampleComponentTwo))
*
* // get a query that will update every world update
* const query = world.query({
* all: [ExampleComponentOne]
* })
* // 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({
* all: [ExampleComponentOne],
* })
* exampleQueryName = this.query((q) => q.all(ExampleComponentOne, ExampleComponentTwo))
*

@@ -80,11 +49,6 @@ * onUpdate() {

key: string;
description: QueryDescription;
conditions: QueryConditions;
bitSets: QueryBitSets;
constructor(world: World, key: string, conditions: QueryConditions, bitSets: QueryBitSets);
/**
* Constructor for a new query instance
* @param world the world the query is in
* @param queryKey the key for the query
*/
constructor(world: World, key: string, description: QueryDescription, bitSets: QueryBitSets);
/**
* Destroys the Query

@@ -94,3 +58,2 @@ */

}
export declare const getQueryDedupeString: (queryDescription: QueryDescription) => string;
/**

@@ -106,37 +69,6 @@ * QueryManager is an internal class that manages Query instances

constructor(world: World);
/**
* Creates a new query by a query description
* @param queryDescription the description of the query to create
*/
createQuery(queryDescription: QueryDescription, owner?: unknown): Query;
/**
* Removes a query from the query manager
* @param query the query to remove
*/
removeQuery(query: Query, owner?: unknown): void;
/**
* Returns whether the query manager has the query
* @param queryDescription the query description to check for
*/
hasQuery(queryDescription: QueryDescription): boolean;
/**
* Updates queries after a component has been added to or removed from an entity
* @param entity the query
*/
findQuery(queryDescription: QueryDescription): Query | undefined;
onEntityComponentChange(entity: Entity): void;
/**
* Updates queries after a query has been removed from the World
* @param entity the query
*/
onEntityRemoved(entity: Entity): void;
/**
* Executes a query and returns a set of the matching Entities.
* By default the query is freshly evaluated, regardless of whether a query with the same description already exists in the world.
* If `options.useExisting` is true, results are taken from an existing query if present.
* @param queryDescription the query description
*/
find(queryDescription: QueryDescription): Entity[];
private matchesQueryConditions;
private getQueryResults;
private getQueryBitSets;
}
import { ComponentDefinition, ComponentInstance } from './component';
import type { QueryDescription } from './query';
import type { QueryDescription } from './query-utils';
import { Query } from './query';

@@ -79,2 +79,6 @@ import type { World } from './world';

requiredQueries: Query[];
/**
* Whether the system has any required queries
*/
hasRequiredQueries: boolean;
};

@@ -123,10 +127,3 @@ constructor(world: World);

/**
* SystemManager is an internal class that manages Systems and calls their lifecycle hooks.
*
* Handles adding and removing systems and providing them with queries via the `QueryManager`.
*
* Maintains the usage of queries by systems and removes queries from the `QueryManager` if no systems are
* using a query.
*
* @private internal class, do not use directly
* @ignore internal
*/

@@ -138,3 +135,3 @@ export declare class SystemManager {

systems: Map<SystemClass, System>;
private sortedSystems;
sortedSystems: System[];
private systemCounter;

@@ -149,8 +146,2 @@ private systemAttachments;

/**
* Updates Systems in the SystemManager
* @param delta the time elapsed in seconds
* @param time the current time in seconds
*/
update(delta: number, time: number): void;
/**
* Destroys all systems

@@ -172,3 +163,3 @@ */

* @param system the system to create the query for
* @param queryDescription the query description
* @param queryDescription the query to create
* @param options the options for the query

@@ -175,0 +166,0 @@ */

@@ -6,3 +6,4 @@ import { type ComponentDefinition } from './component';

import { ComponentPool, EntityPool } from './pools';
import type { Query, QueryDescription } from './query';
import type { Query } from './query';
import type { QueryDescription } from './query-utils';
import { QueryManager } from './query';

@@ -116,3 +117,3 @@ import type { System, SystemAttributes, SystemClass } from './system';

* Creates a Query
* @param queryDescription the query description
* @param queryDescription the query to create
* @returns the Query

@@ -122,8 +123,14 @@ */

/**
* Finds entities that match a given query description.
* @param queryDescription the query description
* Filters entities that match a given query description.
* @param queryDescription the query conditions to match
* @returns entities matching the query description
*/
find(queryDescription: QueryDescription): Entity[];
filter(queryDescription: QueryDescription): Entity[];
/**
* Finds an entity that matches a given query description.
* @param queryDescription the query conditions to match
* @returns the first entity matching the query description
*/
find(queryDescription: QueryDescription): Entity | undefined;
/**
* Registers a Component.

@@ -130,0 +137,0 @@ * For best performance, register all Component classes before initialising the World.

@@ -12,3 +12,3 @@ {

"license": "MIT",
"version": "3.2.0",
"version": "3.3.0",
"homepage": "https://github.com/isaac-mason/arancini",

@@ -28,4 +28,4 @@ "bugs": {

"@babel/core": "^7.22.11",
"@babel/preset-env": "^7.22.10",
"@babel/preset-typescript": "^7.21.4",
"@babel/preset-env": "^7.22.15",
"@babel/preset-typescript": "^7.23.2",
"@mdx-js/react": "^2.3.0",

@@ -35,14 +35,14 @@ "@rollup/plugin-commonjs": "^25.0.4",

"@rollup/plugin-terser": "^0.4.3",
"@rollup/plugin-typescript": "^11.1.1",
"@storybook/addon-essentials": "^7.3.2",
"@storybook/addon-interactions": "^7.3.2",
"@storybook/addon-links": "^7.3.2",
"@storybook/blocks": "^7.3.2",
"@storybook/react": "^7.3.2",
"@storybook/react-vite": "^7.3.2",
"@storybook/testing-library": "^0.2.0",
"@rollup/plugin-typescript": "^11.1.3",
"@storybook/addon-essentials": "^7.5.1",
"@storybook/addon-interactions": "^7.5.1",
"@storybook/addon-links": "^7.5.1",
"@storybook/blocks": "^7.5.1",
"@storybook/react": "^7.5.1",
"@storybook/react-vite": "^7.5.1",
"@storybook/testing-library": "^0.2.2",
"@typescript-eslint/eslint-plugin": "^6.2.0",
"@typescript-eslint/parser": "^6.2.0",
"@vitest/coverage-v8": "^0.33.0",
"eslint": "^8.46.0",
"@vitest/coverage-v8": "^0.34.4",
"eslint": "^8.48.0",
"eslint-config-airbnb": "^19.0.4",

@@ -56,3 +56,3 @@ "eslint-config-airbnb-base": "^15.0.0",

"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-storybook": "^0.6.13",
"eslint-plugin-storybook": "^0.6.15",
"eslint-plugin-typescript-enum": "^2.1.0",

@@ -66,5 +66,5 @@ "prettier": "^3.0.1",

"rollup-plugin-filesize": "^10.0.0",
"storybook": "^7.3.2",
"storybook": "^7.5.1",
"typescript": "^5.1.3",
"vitest": "^0.33.0"
"vitest": "^0.34.3"
},

@@ -71,0 +71,0 @@ "files": [

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc