@daneren2005/shared-memory-ecs 0.0.1 → 1.0.0

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.
@@ -1,7 +1,7 @@
1
1
  import type { TypedArrayConstructor } from '@daneren2005/shared-memory-objects';
2
2
  import type MemoryComponent from './memory-component';
3
3
  import type { ComponentTypedArray } from './memory-component';
4
- import type Entity from './entity';
4
+ import type BaseEntity from './entity';
5
5
  export interface BaseComponent {
6
6
  index: number;
7
7
  }
@@ -9,7 +9,7 @@ export type ComponentMap = Record<string, BaseComponent>;
9
9
  export interface ComponentDefinition<Component extends BaseComponent, T extends ComponentTypedArray = ComponentTypedArray, Config = any, Serialization = any> {
10
10
  type: TypedArrayConstructor<T>;
11
11
  size: number;
12
- load(entity: Entity, memory: MemoryComponent<T>, config: Config): Component;
12
+ load(entity: BaseEntity, memory: MemoryComponent<T>, config: Config): Component;
13
13
  save?(component: Component): Serialization;
14
14
  }
15
15
  export type ComponentRegistry<C extends ComponentMap> = {
package/dist/entity.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  import { EventEmitter } from 'eventemitter3';
2
- import type World from './world';
2
+ import type BaseWorld from './world';
3
3
  import type { ComponentMap } from './component-definition';
4
- export default class Entity<C extends ComponentMap = ComponentMap> extends EventEmitter {
4
+ export default class BaseEntity<C extends ComponentMap = ComponentMap> extends EventEmitter {
5
5
  static eidCounter: number;
6
6
  readonly eid: number;
7
7
  id?: string;
8
8
  config?: any;
9
- world: World<C>;
9
+ world: BaseWorld<C>;
10
10
  components: Partial<C>;
11
11
  dead: boolean;
12
12
  isStatic: boolean;
13
- constructor(world: World<C>, config?: any);
13
+ constructor(world: BaseWorld<C>, config?: any);
14
14
  loadComponent<K extends keyof C>(name: K, config: any): C[K];
15
15
  removeComponent<K extends keyof C>(name: K): void;
16
16
  setComponent<K extends keyof C, P extends keyof C[K]>(componentName: K, prop: P, value: C[K][P]): void;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { default as World } from './world';
1
+ export { default as BaseWorld } from './world';
2
2
  export type { WorldOptions } from './world';
3
- export { default as Entity } from './entity';
3
+ export { default as BaseEntity } from './entity';
4
4
  export { default as MemoryComponent } from './memory-component';
5
5
  export type { ComponentTypedArray } from './memory-component';
6
- export type { BaseComponent, ComponentMap, ComponentDefinition, ComponentRegistry } from './component-definition';
6
+ export type { BaseComponent, ComponentMap, ComponentDefinition, ComponentRegistry, } from './component-definition';
7
7
  export { default as System } from './systems/system';
8
8
  export type { SystemConfig } from './systems/system';
9
9
  export { default as IterableSystem } from './systems/iterable-system';
@@ -11,7 +11,7 @@ export type { IterableSystemConfig } from './systems/iterable-system';
11
11
  export { default as EntitySystem } from './systems/entity-system';
12
12
  export type { EntitySystemConfig } from './systems/entity-system';
13
13
  export { default as ComponentSystem } from './systems/component-system';
14
- export type { ComponentSystemConfig, ComponentSystemQuery, ComponentSystemWorld, ComponentSystemCallbacks, EntityUpdateComponents, EntityQueryComponents, EntityUpdateFunction, EntityUpdatePreRunFunction, EntityRemovedFunction, UpdateEntityConfig, UpdateEntityConfigObject } from './systems/component-system';
14
+ export type { ComponentSystemConfig, ComponentSystemQuery, ComponentSystemWorld, ComponentSystemCallbacks, EntityUpdateComponents, EntityQueryComponents, EntityUpdateFunction, EntityUpdatePreRunFunction, EntityRemovedFunction, UpdateEntityConfig, UpdateEntityConfigObject, } from './systems/component-system';
15
15
  export { default as WebWorker } from './systems/workers/web-worker';
16
16
  export { default as ComponentWebWorker } from './systems/workers/component-web-worker';
17
17
  export { default as createComponentWorker } from './systems/workers/create-component-worker';
package/dist/index.js CHANGED
@@ -467,6 +467,6 @@ function g(e) {
467
467
  self.postMessage(e);
468
468
  }
469
469
  //#endregion
470
- export { f as ComponentSystem, u as ComponentWebWorker, a as Entity, c as EntitySystem, s as IterableSystem, i as MemoryComponent, o as System, l as WebWorker, m as World, h as createComponentWorker };
470
+ export { a as BaseEntity, m as BaseWorld, f as ComponentSystem, u as ComponentWebWorker, c as EntitySystem, s as IterableSystem, i as MemoryComponent, o as System, l as WebWorker, h as createComponentWorker };
471
471
 
472
472
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/memory-component.ts","../src/entity.ts","../src/systems/system.ts","../src/systems/iterable-system.ts","../src/systems/entity-system.ts","../src/systems/workers/web-worker.ts","../src/systems/workers/component-web-worker.ts","../src/systems/component-system.ts","../src/world.ts","../src/systems/workers/create-component-worker.ts"],"sourcesContent":["import { LocalPool, type MemoryHeap, type TypedArrayConstructor } from '@daneren2005/shared-memory-objects';\n\n// The typed arrays a MemoryComponent can be backed by. Kept narrower than the package's TypedArray\n// union on purpose since these are the only types we allocate blocks of.\nexport type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;\n\n// A pool of same sized blocks living inside a shared MemoryHeap. Each component instance owns one\n// block (referenced by its index) so component data can be shared with worker threads.\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: LocalPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number) {\n\t\tthis.heap = heap;\n\t\tthis.pool = new LocalPool(heap, {\n\t\t\ttype,\n\t\t\tdataLength\n\t\t});\n\t}\n\n\tget length() {\n\t\treturn this.pool.length;\n\t}\n\tget rawLength() {\n\t\treturn this.pool.bufferLength;\n\t}\n\n\tcreate(values: Array<number>): number {\n\t\treturn this.pool.push(values);\n\t}\n\n\tgetBlock(index: number): T {\n\t\treturn this.pool.at(index);\n\t}\n\tget(index: number, dataIndex: number): number {\n\t\treturn this.pool.get(index, dataIndex);\n\t}\n\tset(index: number, dataIndex: number, value: number) {\n\t\tlet array = this.pool.at(index);\n\t\tarray[dataIndex] = value;\n\t}\n\n\tdelete(index: number) {\n\t\tthis.pool.deleteIndex(index);\n\t}\n\tclear() {\n\t\tthis.pool.clear();\n\t}\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type World from './world';\nimport type { ComponentMap } from './component-definition';\n\n// A bare entity: an id, an eid, and a bag of memory-backed components. There are intentionally no\n// direct property setters/getters (x/y/visible/etc), no faction relationship, and no required\n// components - all of that lives in the game that consumes this library.\nexport default class Entity<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\tstatic eidCounter = 1;\n\n\t// eid is a fast numeric reference for internal lookups (worker threads, caches). id is the\n\t// stable string reference used by save data / cross-entity references.\n\treadonly eid: number;\n\tid?: string;\n\tconfig?: any;\n\n\tworld: World<C>;\n\tcomponents: Partial<C> = {};\n\tdead = false;\n\tisStatic = false;\n\n\tconstructor(world: World<C>, config?: any) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.eid = Entity.eidCounter++;\n\t\tif(config) {\n\t\t\tthis.load(config);\n\t\t}\n\t}\n\n\tloadComponent<K extends keyof C>(name: K, config: any): C[K] {\n\t\tconst definition = this.world.registry[name];\n\t\tconst memoryComponent = this.world.components[name];\n\t\t// Entity is invariant over C (registry/components), so widen to the definition's default Entity.\n\t\tconst component = definition.load(this as unknown as Entity, memoryComponent, config) as C[K];\n\t\tthis.components[name] = component;\n\t\tthis.emit('component-added', name, component);\n\n\t\treturn component;\n\t}\n\tremoveComponent<K extends keyof C>(name: K) {\n\t\tconst component = this.components[name];\n\t\tif(component) {\n\t\t\tthis.world.components[name].delete(component.index);\n\t\t\tdelete this.components[name];\n\t\t\tthis.emit('component-removed', name);\n\t\t}\n\t}\n\tsetComponent<K extends keyof C, P extends keyof C[K]>(componentName: K, prop: P, value: C[K][P]) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\t// TS can't verify writing to a property of the generic C[K] by a keyof C[K] key, so index through a record.\n\t\t(component as unknown as Record<P, C[K][P]>)[prop] = value;\n\t\tthis.emit('component-property-updated', componentName, prop, value);\n\t}\n\t/**\n\t * NOTE: Does not emit component-property-updated!\n\t */\n\tsetComponentBulk<K extends keyof C>(componentName: K, values: Partial<C[K]>) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tObject.assign(component, values);\n\t}\n\tdeleteComponent<K extends keyof C>(componentName: K, prop: keyof C[K]) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tdelete (component as Partial<C[K]>)[prop];\n\t\tthis.emit('component-property-deleted', componentName, prop);\n\t}\n\n\tdeleteAllComponentMemory() {\n\t\tfor(let name of Object.keys(this.components) as Array<keyof C>) {\n\t\t\tconst component = this.components[name];\n\t\t\tif(component) {\n\t\t\t\tthis.world.components[name].delete(component.index);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Loads only component data: every key in the config that maps to a registered component is handed to that component's loader.\n\tload(config: any) {\n\t\tfor(let name in config) {\n\t\t\tif(name in this.world.registry) {\n\t\t\t\tthis.loadComponent(name as keyof C, config[name]);\n\t\t\t}\n\t\t}\n\n\t\tthis.config = config;\n\t}\n\tsave() {\n\t\tconst config: { [key: string]: any } = {};\n\n\t\tfor(let name of Object.keys(this.components) as Array<keyof C>) {\n\t\t\tconst definition = this.world.registry[name];\n\t\t\tconst component = this.components[name];\n\t\t\tif(definition.save && component) {\n\t\t\t\tconfig[name as string] = definition.save(component);\n\t\t\t}\n\t\t}\n\n\t\treturn config;\n\t}\n\t// Hook for games that need a second pass once every entity in a load batch exists.\n\tfinishLoading() {}\n}\n","import type World from '../world';\nimport type { ComponentMap } from '../component-definition';\n\n// Base system: runs on an optional fixed timestep (deltaBetweenRuns) and is driven by World#update.\nexport default abstract class System<C extends ComponentMap = ComponentMap> {\n\tworld: World<C>;\n\tname: string;\n\tcurrentDelta: number = 0;\n\tdeltaBetweenRuns: number;\n\tfirstRun: boolean;\n\n\tconstructor(world: World<C>, options: SystemConfig = { name: 'System' }) {\n\t\tthis.name = options.name;\n\t\tthis.world = world;\n\n\t\tthis.deltaBetweenRuns = options.deltaBetweenRuns ?? 0;\n\t\tthis.firstRun = options.firstRun !== undefined ? options.firstRun : false;\n\t}\n\n\tinit(): void | Promise<void> {}\n\n\tclear() {\n\t\tthis.currentDelta = 0;\n\t}\n\tfinishLoading() {}\n\n\tupdate(elapsedTime: number): boolean {\n\t\tthis.currentDelta += elapsedTime;\n\n\t\tif(this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {\n\t\t\tlet leftOverDelta = 0;\n\t\t\tif(this.deltaBetweenRuns > 0) {\n\t\t\t\t// Without this if we take 100ms to run (ie: IterableSystem across multiple frames) then we will end up actually running this in 300ms total instead of again in 100ms for a total of 200ms\n\t\t\t\t// With firstRun this ends up calling run(0) the first time - this makes it so things like events are will trigger on the second instead of triggering a 1 second timer at 1.0166 seconds\n\t\t\t\tleftOverDelta = this.currentDelta % this.deltaBetweenRuns;\n\t\t\t}\n\n\t\t\tthis.run(this.currentDelta - leftOverDelta);\n\t\t\tthis.currentDelta = leftOverDelta;\n\t\t\tthis.firstRun = false;\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tabstract run(elapsedTime: number): void;\n\n\tshouldRun(): boolean {\n\t\treturn true;\n\t}\n\n\tdestroy() {}\n}\n\nexport interface SystemConfig {\n\tname: string\n\tdeltaBetweenRuns?: number\n\t// Defaults to false\n\tfirstRun?: boolean\n}\n","import type World from '../world';\nimport type { ComponentMap } from '../component-definition';\nimport System, { type SystemConfig } from './system';\n\n// A system that iterates a list of instances, spreading the work across multiple frames if a single\n// pass would exceed maxMsPerFrame.\nexport default abstract class IterableSystem<C extends ComponentMap, T> extends System<C> {\n\tremainingInstancesToRun: Array<T> = [];\n\tremainingInstancesStartTime: number | null = null;\n\titerationsPerCheck: number;\n\tmaxMsPerFrame: number;\n\n\tconstructor(world: World<C>, options: IterableSystemConfig) {\n\t\tsuper(world, options);\n\n\t\tthis.iterationsPerCheck = options.iterationsPerCheck ?? 1;\n\t\tthis.maxMsPerFrame = options.maxMsPerFrame ?? 10;\n\t}\n\n\tclear() {\n\t\tsuper.clear();\n\n\t\tthis.remainingInstancesToRun = [];\n\t\tthis.remainingInstancesStartTime = null;\n\t}\n\n\tupdate(elapsedTime: number): boolean {\n\t\tif(this.remainingInstancesToRun.length) {\n\t\t\tthis.runIterables(this.remainingInstancesToRun, this.remainingInstancesStartTime ?? 0);\n\t\t\tthis.currentDelta += elapsedTime;\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn super.update(elapsedTime);\n\t\t}\n\t}\n\trun(elapsedTime: number): void {\n\t\tlet iterables = this.getIterables();\n\t\tthis.runIterables(iterables, elapsedTime);\n\t}\n\trunIterables(iterables: Array<T>, elapsedTime: number) {\n\t\tlet started = performance.now();\n\t\tthis.beforeRunIterables();\n\t\tfor(let i = 0; i < iterables.length; i++) {\n\t\t\tthis.updateIterable(iterables[i], elapsedTime);\n\n\t\t\tif(i % this.iterationsPerCheck === 0) {\n\t\t\t\tlet now = performance.now();\n\t\t\t\tif(now - started >= this.maxMsPerFrame) {\n\t\t\t\t\tthis.remainingInstancesToRun = iterables.slice(i + 1);\n\t\t\t\t\tthis.remainingInstancesStartTime = elapsedTime;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.remainingInstancesToRun = [];\n\t\tthis.remainingInstancesStartTime = null;\n\t}\n\tbeforeRunIterables() {}\n\n\tabstract getIterables(): Array<T>;\n\tabstract updateIterable(iterable: T, elapsedTime: number): void;\n}\n\nexport interface IterableSystemConfig extends SystemConfig {\n\titerationsPerCheck?: number\n\tmaxMsPerFrame?: number\n}\n","import type World from '../world';\nimport type Entity from '../entity';\nimport type { ComponentMap } from '../component-definition';\nimport IterableSystem, { type IterableSystemConfig } from './iterable-system';\n\n// Iterates the entities that own a given set of components on the main thread. Entities are added\n// and removed automatically as the world emits entity-added / entity-removed / component changes.\nexport default abstract class EntitySystem<C extends ComponentMap, T extends Entity<C> = Entity<C>> extends IterableSystem<C, T> {\n\tentities: Array<T> = [];\n\toptions: EntitySystemConfig<C>;\n\n\tconstructor(world: World<C>, options: EntitySystemConfig<C> = { name: 'EntitySystem' }) {\n\t\tif(!options.iterationsPerCheck) {\n\t\t\toptions.iterationsPerCheck = 10;\n\t\t}\n\t\tif(!options.maxMsPerFrame) {\n\t\t\toptions.maxMsPerFrame = 4;\n\t\t}\n\n\t\tsuper(world, options);\n\t\tthis.options = options;\n\n\t\tworld.on('entity-added', (entity: Entity<C>) => {\n\t\t\tif(this.checkAddEntity(entity) && this.options.updateEntityOnAdd) {\n\t\t\t\tthis.updateEntity(entity as T, 0);\n\t\t\t}\n\t\t});\n\t\tworld.on('entity-removed', (entity: Entity<C>) => {\n\t\t\tthis.removeEntity(entity);\n\t\t});\n\n\t\tworld.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t}\n\n\tgetIterables(): Array<T> {\n\t\treturn this.entities.filter(entity => !entity.dead);\n\t}\n\tupdateIterable(entity: T, elapsedTime: number): void {\n\t\tif(entity.dead) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateEntity(entity, elapsedTime);\n\t}\n\tfilterEntity(entity: Entity<C>): boolean {\n\t\treturn !entity.isStatic;\n\t}\n\tisEntityInSystem(entity: Entity<C>) {\n\t\treturn this.entities.indexOf(entity as T) !== -1;\n\t}\n\tabstract updateEntity(entity: T, elapsedTime: number): void;\n\n\tcheckAddEntity(entity: Entity<C>): boolean {\n\t\tif(this.options.components && this.options.components.filter(component => !!entity.components[component]).length !== this.options.components.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(this.filterEntity(entity)) {\n\t\t\tthis.entities.push(entity as T);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tremoveEntity(entity: Entity<C>) {\n\t\tlet index = this.entities.indexOf(entity as T);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t}\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.length > 0;\n\t}\n}\n\nexport interface EntitySystemConfig<C extends ComponentMap> extends IterableSystemConfig {\n\tcomponents?: Array<keyof C>\n\tupdateEntityOnAdd?: boolean\n}\n","// Minimal Worker-like base used for the main-thread fallback when real Web Workers / SharedArrayBuffer\n// are unavailable. Params are intentionally loose since this is the (serialization) boundary that\n// mirrors the DOM Worker interface.\nexport default abstract class WebWorker {\n\tabstract postMessage(message: any): void | Promise<void>;\n\tonmessage(message: any, transferrables: Array<any> = []): void {\n\n\t}\n}\n","import WebWorker from './web-worker';\nimport type ComponentWorkerMessage from './component-worker-message';\nimport type { ComponentMap } from '../../component-definition';\nimport type { ComponentSystemCallbacks, EntityQueryComponents, EntityUpdateComponents, EntityUpdateFunction, UpdateEntityConfigObject } from '../component-system';\n\n// Main-thread fallback that runs the update function synchronously when real Web Workers /\n// SharedArrayBuffer are unavailable. Because it runs in-process it can pass the components straight\n// through without caching them by entity id.\nexport default class ComponentWebWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>> extends WebWorker {\n\tprivate updateFunction: EntityUpdateFunction<C, T>;\n\n\tconstructor(updateFunction: EntityUpdateFunction<C, T>) {\n\t\tsuper();\n\t\tthis.updateFunction = updateFunction;\n\t}\n\n\tpostMessage(message: ComponentWorkerMessage): void {\n\t\tif(message.type === 'init') {\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'loaded'\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\n\t\t\tlet callbacks: ComponentSystemCallbacks<C> = {\n\t\t\t\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'component-property-updated',\n\t\t\t\t\t\targs: [componentName, prop, value]\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\tif(this.updateFunction.preRun) {\n\t\t\t\tthis.updateFunction.preRun(message.world, message.entities as Array<UpdateEntityConfigObject<T>>, message.queries as EntityQueryComponents<C>, callbacks);\n\t\t\t}\n\t\t\tmessage.entities.forEach(entity => {\n\t\t\t\t// Should not be called\n\t\t\t\tif(typeof entity === 'number') {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.updateFunction(message.world, entity.entityId, entity.components as T, message.queries as EntityQueryComponents<C>, callbacks);\n\t\t\t});\n\n\t\t\tif(this.updateFunction.entityRemoved) {\n\t\t\t\tfor(let entityId of message.removed) {\n\t\t\t\t\tthis.updateFunction.entityRemoved(message.world, entityId, callbacks);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime: 0,\n\t\t\t\tevents: entityEvents\n\t\t\t});\n\t\t}\n\t}\n\n\tonMessageTyped(message: ComponentWorkerMessage) {\n\t\tthis.onmessage({\n\t\t\tdata: message\n\t\t});\n\t}\n}\n","import type World from '../world';\nimport type Entity from '../entity';\nimport type { BaseComponent, ComponentMap } from '../component-definition';\nimport type { ComponentTypedArray } from '../memory-component';\nimport System, { type SystemConfig } from './system';\nimport type ComponentWorkerMessage from './workers/component-worker-message';\nimport ComponentWebWorker from './workers/component-web-worker';\n\nconst MAIN_QUERY_NAME = '___main';\n\n// Runs an update function over the raw shared-memory blocks of its matched entities, ideally on a\n// separate thread. When Web Workers + SharedArrayBuffer are available the work happens on `getWorker()`;\n// otherwise it falls back to running synchronously on the main thread via ComponentWebWorker.\n//\n// This is deliberately free of any game concepts (no factions, fog of war, position, etc). Games\n// inject whatever extra per-run data they need through `addDataToWorld`.\nexport default abstract class ComponentSystem<C extends ComponentMap = ComponentMap, T extends EntityUpdateComponents<C> = EntityUpdateComponents<C>> extends System<C> {\n\tentities: Array<Entity<C>> = [];\n\toptions: ComponentSystemConfig<C, T>;\n\n\tworker: Worker | ComponentWebWorker<C, T>;\n\tisWorkerThread: boolean;\n\n\tprivate loaded = false;\n\tprivate loadingPromise: { promise: Promise<void>, resolve: (value: void | PromiseLike<void>) => void } | null = null;\n\tprivate isRunning = false;\n\tprivate queryEntityComponentCache: { [key: string]: { [key: number]: { entity: Entity<C>, components: T } } } = {};\n\tprivate queryEntities: { [key: string]: Array<Entity<C>> } = {};\n\tprivate removedEntityBuffer: Array<number> = [];\n\n\t// Optional hook for subclasses to attach extra data to the world object sent to the worker.\n\taddDataToWorld?(world: ComponentSystemWorld): void;\n\n\tconstructor(world: World<C>, options: ComponentSystemConfig<C, T>) {\n\t\tsuper(world, options);\n\t\tthis.options = options;\n\t\tObject.keys(this.options.queries ?? {}).forEach(queryName => {\n\t\t\tthis.queryEntities[queryName] = [];\n\t\t});\n\n\t\tworld.on('entity-added', (entity: Entity<C>) => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t\tworld.on('entity-removed', (entity: Entity<C>) => {\n\t\t\tthis.removeEntity(entity);\n\t\t});\n\n\t\tworld.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\n\t\tif(!options.forceMainThread && typeof globalThis.Worker !== 'undefined' && typeof globalThis.SharedArrayBuffer !== 'undefined') {\n\t\t\tthis.worker = options.getWorker();\n\t\t\tthis.isWorkerThread = true;\n\t\t} else {\n\t\t\tthis.worker = new ComponentWebWorker(options.updateFunction);\n\t\t\tthis.isWorkerThread = false;\n\t\t}\n\n\t\tthis.initWorker();\n\t}\n\n\tprivate initWorker() {\n\t\tthis.worker.onmessage = (e: MessageEvent) => {\n\t\t\tlet message = e.data as ComponentWorkerMessage;\n\t\t\tif(message.type === 'loaded') {\n\t\t\t\tthis.loaded = true;\n\t\t\t\tif(this.loadingPromise) {\n\t\t\t\t\tthis.loadingPromise.resolve();\n\t\t\t\t\tthis.loadingPromise = null;\n\t\t\t\t}\n\t\t\t} else if(message.type === 'run-complete') {\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tif(this.isWorkerThread) {\n\t\t\t\t\tthis.world.emit(`system-${this.name}-worker-finished`, message.runTime);\n\t\t\t\t}\n\n\t\t\t\tmessage.events.forEach(event => {\n\t\t\t\t\tconst entity = this.queryEntityComponentCache[MAIN_QUERY_NAME][event.entityId]?.entity ?? this.entities.find(entity => entity.eid === event.entityId);\n\t\t\t\t\tif(!entity) {\n\t\t\t\t\t\tconsole.warn(`Could not find entity with id ${event.entityId}`);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tentity.emit(event.event, ...event.args);\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage = {\n\t\t\ttype: 'init'\n\t\t};\n\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tinit(): Promise<void> | void {\n\t\tif(this.loaded) {\n\t\t\treturn;\n\t\t} else if(this.loadingPromise) {\n\t\t\treturn this.loadingPromise.promise;\n\t\t}\n\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\tthis.loadingPromise = {\n\t\t\tpromise,\n\t\t\tresolve\n\t\t};\n\t\treturn promise;\n\t}\n\n\tupdate(elapsedTime: number): boolean {\n\t\t// Only run worker if the last run completed already\n\t\tif(this.isRunning) {\n\t\t\tthis.currentDelta += elapsedTime;\n\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn super.update(elapsedTime);\n\t\t}\n\t}\n\trun(elapsedTime: number): void {\n\t\tconst world: ComponentSystemWorld = {\n\t\t\tgameTime: this.world.gameTime,\n\t\t\telapsedTime\n\t\t};\n\t\tthis.addDataToWorld?.(world);\n\n\t\tthis.isRunning = true;\n\t\tlet entities = this.runQuery(MAIN_QUERY_NAME, this.entities, this.options);\n\t\tlet queries: { [key: string]: Array<UpdateEntityConfig<T>> } = {};\n\t\tObject.entries(this.options.queries ?? {}).forEach(([queryKey, query]) => {\n\t\t\tqueries[queryKey] = this.runQuery(queryKey, this.queryEntities[queryKey] ?? [], query);\n\t\t});\n\t\tlet message: ComponentWorkerMessage = {\n\t\t\ttype: 'run',\n\t\t\tworld,\n\t\t\tentities,\n\t\t\tqueries,\n\t\t\tremoved: this.removedEntityBuffer\n\t\t};\n\t\tthis.worker.postMessage(message);\n\t\tthis.removedEntityBuffer = [];\n\t}\n\n\trunQuery(queryName: string, entities: Array<Entity<C>>, query: ComponentSystemQuery<C>): Array<UpdateEntityConfig<T>> {\n\t\tlet filteredEntities: Array<UpdateEntityConfig<T>> = [];\n\n\t\tlet cache = this.queryEntityComponentCache[queryName];\n\t\tif(!cache) {\n\t\t\tcache = this.queryEntityComponentCache[queryName] = {};\n\t\t}\n\t\tentities.forEach(entity => {\n\t\t\tif(entity.dead) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet components = cache[entity.eid]?.components;\n\t\t\t// Cache components memory since doing the lookup is kind of slow\n\t\t\tif(!components) {\n\t\t\t\tcomponents = {} as T;\n\t\t\t\t[\n\t\t\t\t\t...query.required,\n\t\t\t\t\t...query.optional ?? []\n\t\t\t\t].forEach(componentName => {\n\t\t\t\t\tconst component = entity.components[componentName];\n\t\t\t\t\tconst memoryComponent = this.world.components[componentName];\n\t\t\t\t\tif(component && memoryComponent) {\n\t\t\t\t\t\tcomponents[componentName] = memoryComponent.getBlock(component.index) as T[typeof componentName];\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tcache[entity.eid] = {\n\t\t\t\t\tentity,\n\t\t\t\t\tcomponents\n\t\t\t\t};\n\n\t\t\t\tfilteredEntities.push({\n\t\t\t\t\tentityId: entity.eid,\n\t\t\t\t\tcomponents\n\t\t\t\t});\n\t\t\t} else if(this.isWorkerThread) {\n\t\t\t\t// For worker threads it is slow to send the components in postMessage - so thread caches them after first time sent\n\t\t\t\tfilteredEntities.push(entity.eid);\n\t\t\t} else {\n\t\t\t\t// For main thread execution it is faster to just pass the components to be used directly\n\t\t\t\tfilteredEntities.push({\n\t\t\t\t\tentityId: entity.eid,\n\t\t\t\t\tcomponents\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\treturn filteredEntities;\n\t}\n\n\tisEntityInSystem(entity: Entity<C>) {\n\t\treturn this.entities.indexOf(entity) !== -1;\n\t}\n\tprivate matchesQuery(entity: Entity<C>, query: ComponentSystemQuery<C>): boolean {\n\t\tif(entity.dead) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(query.required.find(component => !entity.components[component])) {\n\t\t\treturn false;\n\t\t}\n\t\tif(query.not?.find(component => !!entity.components[component])) {\n\t\t\treturn false;\n\t\t}\n\t\tif(query.filter && !query.filter(entity)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\tprivate updateEntityList(list: Array<Entity<C>>, entity: Entity<C>, shouldInclude: boolean) {\n\t\tlet index = list.indexOf(entity);\n\t\tif(shouldInclude) {\n\t\t\tif(index === -1) {\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t} else if(index !== -1) {\n\t\t\tlist.splice(index, 1);\n\t\t}\n\t}\n\n\tcheckAddEntity(entity: Entity<C>): boolean {\n\t\tconst shouldAddToMain = this.matchesQuery(entity, this.options);\n\t\tthis.updateEntityList(this.entities, entity, shouldAddToMain);\n\n\t\tObject.entries(this.options.queries ?? {}).forEach(([queryName, query]) => {\n\t\t\tconst queryList = this.queryEntities[queryName] ?? (this.queryEntities[queryName] = []);\n\t\t\tthis.updateEntityList(queryList, entity, this.matchesQuery(entity, query));\n\t\t});\n\n\t\t// Invalidate cached components so they are rebuilt with current components on next runQuery\n\t\tObject.values(this.queryEntityComponentCache).forEach(cache => {\n\t\t\tif(cache[entity.eid]) {\n\t\t\t\tdelete cache[entity.eid];\n\t\t\t}\n\t\t});\n\n\t\treturn shouldAddToMain;\n\t}\n\tremoveEntity(entity: Entity<C>) {\n\t\tthis.updateEntityList(this.entities, entity, false);\n\t\tObject.values(this.queryEntities).forEach(list => {\n\t\t\tthis.updateEntityList(list, entity, false);\n\t\t});\n\n\t\tObject.values(this.queryEntityComponentCache).forEach(cache => {\n\t\t\tif(cache[entity.eid]) {\n\t\t\t\tdelete cache[entity.eid];\n\t\t\t}\n\t\t});\n\t\tthis.removedEntityBuffer.push(entity.eid);\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.length > 0;\n\t}\n\n\tdestroy() {\n\t\tif('terminate' in this.worker) {\n\t\t\tthis.worker.terminate();\n\t\t}\n\t}\n}\n\nexport type EntityUpdateComponents<C extends ComponentMap = ComponentMap> = { [K in keyof C]?: ComponentTypedArray };\nexport type EntityQueryComponents<C extends ComponentMap = ComponentMap> = { [key: string]: Array<{ entityId: number, components: EntityUpdateComponents<C> }> };\ntype EntityUpdateFunctionImpl<C extends ComponentMap, T extends EntityUpdateComponents<C>> = (world: ComponentSystemWorld, entityId: number, components: T, queries: EntityQueryComponents<C>, callbacks: ComponentSystemCallbacks<C>) => void;\nexport type EntityUpdateFunction<C extends ComponentMap, T extends EntityUpdateComponents<C> = EntityUpdateComponents<C>> = EntityUpdateFunctionImpl<C, T> & { preRun?: EntityUpdatePreRunFunction<C, T>, entityRemoved?: EntityRemovedFunction<C> };\nexport type EntityUpdatePreRunFunction<C extends ComponentMap, T extends EntityUpdateComponents<C>> = (world: ComponentSystemWorld, entities: Array<UpdateEntityConfigObject<T>>, queries: EntityQueryComponents<C>, callbacks: ComponentSystemCallbacks<C>) => void;\nexport type EntityRemovedFunction<C extends ComponentMap = ComponentMap> = (world: ComponentSystemWorld, entityId: number, callbacks: ComponentSystemCallbacks<C>) => void;\nexport type UpdateEntityConfig<T extends EntityUpdateComponents = EntityUpdateComponents> = number | UpdateEntityConfigObject<T>;\nexport type UpdateEntityConfigObject<T extends EntityUpdateComponents> = {\n\tentityId: number\n\tcomponents: T\n};\n\n// Base per-run world data. gameTime + elapsedTime are always present; games attach anything else\n// they need via addDataToWorld, which is why an index signature is included.\nexport interface ComponentSystemWorld {\n\tgameTime: number\n\telapsedTime: number\n\t[key: string]: unknown\n}\nexport interface ComponentSystemCallbacks<C extends ComponentMap = ComponentMap> {\n\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]): void\n}\n\nexport interface ComponentSystemQuery<C extends ComponentMap = ComponentMap> {\n\trequired: Array<keyof C>\n\toptional?: Array<keyof C>\n\tnot?: Array<keyof C>\n\tfilter?: (entity: Entity<C>) => boolean\n}\n\nexport interface ComponentSystemConfig<C extends ComponentMap, T extends EntityUpdateComponents<C>> extends SystemConfig, ComponentSystemQuery<C> {\n\tupdateFunction: EntityUpdateFunction<C, T>\n\tgetWorker: () => Worker\n\tforceMainThread?: boolean\n\n\tqueries?: { [key: string]: ComponentSystemQuery<C> }\n}\n\n// Re-exported so BaseComponent is reachable from the systems barrel if needed.\nexport type { BaseComponent };\n","import { EventEmitter } from 'eventemitter3';\nimport { MAX_BYTE_OFFSET_LENGTH, MemoryHeap } from '@daneren2005/shared-memory-objects';\nimport MemoryComponent from './memory-component';\nimport Entity from './entity';\nimport type System from './systems/system';\nimport EntitySystem from './systems/entity-system';\nimport ComponentSystem from './systems/component-system';\nimport type { ComponentMap, ComponentRegistry } from './component-definition';\n\nconst DEFAULT_HEAP_SIZE = MAX_BYTE_OFFSET_LENGTH;\n\nexport interface WorldOptions {\n\theapSize?: number\n}\n\n// A simple wrapper around a set of entities + systems. On construction it creates one\n// MemoryComponent per entry in the component registry so entities can load/save themselves without\n// each game re-declaring loaders/savers. It has no game specific load/save/terrain/faction logic -\n// that all belongs in the game that consumes this library.\nexport default class World<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\theap: MemoryHeap;\n\tregistry: ComponentRegistry<C>;\n\tcomponents: { [K in keyof C]: MemoryComponent };\n\n\tentities: Array<Entity<C>> = [];\n\tentitiesByEid: { [eid: number]: Entity<C> } = {};\n\tsystems: Array<System<C>> = [];\n\n\tgameTime = 0;\n\tdestroyed = false;\n\n\tconstructor(registry: ComponentRegistry<C>, options: WorldOptions = {}) {\n\t\tsuper();\n\n\t\tthis.registry = registry;\n\t\tthis.heap = new MemoryHeap({ bufferSize: options.heapSize ?? DEFAULT_HEAP_SIZE });\n\n\t\tconst components = {} as { [K in keyof C]: MemoryComponent };\n\t\tfor(let name of Object.keys(registry) as Array<keyof C>) {\n\t\t\tconst definition = registry[name];\n\t\t\tcomponents[name] = new MemoryComponent(this.heap, definition.type, definition.size);\n\t\t}\n\t\tthis.components = components;\n\t}\n\n\tasync init() {\n\t\tawait Promise.all(this.systems.map(system => system.init()).filter(promise => promise instanceof Promise));\n\t}\n\n\taddEntity(entity: Entity<C>, created = true): Entity<C> {\n\t\tthis.entities.push(entity);\n\t\tthis.entitiesByEid[entity.eid] = entity;\n\t\tentity.world = this;\n\n\t\tentity.on('component-added', (name: keyof C) => {\n\t\t\tthis.addEntityToComponentSystem(entity, name);\n\t\t});\n\t\tentity.on('component-removed', (name: keyof C) => {\n\t\t\tthis.removeEntityFromComponentSystem(entity, name);\n\t\t});\n\n\t\tif(created) {\n\t\t\tentity.finishLoading();\n\t\t}\n\t\tthis.emit('entity-added', entity);\n\n\t\treturn entity;\n\t}\n\tloadEntity(config: any, created = true): Entity<C> {\n\t\treturn this.addEntity(new Entity<C>(this, config), created);\n\t}\n\tremoveEntity(entity: Entity<C>) {\n\t\tlet index = this.entities.indexOf(entity);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t\tdelete this.entitiesByEid[entity.eid];\n\t\t\tthis.emit('entity-removed', entity);\n\t\t}\n\n\t\tentity.deleteAllComponentMemory();\n\t}\n\tgetEntityByEid(eid: number): Entity<C> | undefined {\n\t\treturn this.entitiesByEid[eid];\n\t}\n\n\taddSystem<T extends System<C>>(system: T): T {\n\t\tthis.systems.push(system);\n\t\treturn system;\n\t}\n\taddSystemIfNotExists(system: System<C>) {\n\t\tlet index = this.systems.findIndex(otherSystem => system.name === otherSystem.name);\n\t\tif(index === -1) {\n\t\t\tthis.systems.push(system);\n\t\t}\n\t}\n\tremoveSystem(name: string) {\n\t\tlet index = this.systems.findIndex(system => system.name === name);\n\t\tif(index !== -1) {\n\t\t\tthis.systems.splice(index, 1);\n\t\t}\n\t}\n\n\tupdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\tthis.gameTime += elapsedTime;\n\n\t\tlet lastSystemError: Error | null = null;\n\t\tthis.systems.forEach(system => {\n\t\t\tlet shouldRun = true;\n\t\t\tlet ran = false;\n\t\t\tlet failed = false;\n\t\t\tthis.emit(`system-${system.name}-started`);\n\t\t\ttry {\n\t\t\t\tshouldRun = system.shouldRun();\n\t\t\t\tif(shouldRun) {\n\t\t\t\t\tran = system.update(elapsedTime);\n\t\t\t\t}\n\t\t\t} catch(e) {\n\t\t\t\tconst error = e as Error;\n\t\t\t\tconsole.error(error.message, error);\n\t\t\t\tfailed = true;\n\t\t\t\tlastSystemError = error;\n\t\t\t}\n\t\t\tthis.emit(`system-${system.name}-finished`, {\n\t\t\t\tran,\n\t\t\t\tshouldRun,\n\t\t\t\tfailed\n\t\t\t});\n\t\t});\n\n\t\treturn {\n\t\t\tlastSystemError\n\t\t};\n\t}\n\n\taddEntityToComponentSystem(entity: Entity<C>, component: keyof C) {\n\t\tthis.systems.forEach(system => {\n\t\t\tif(system instanceof EntitySystem && system.options.components?.includes(component)) {\n\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t} else if(system instanceof ComponentSystem) {\n\t\t\t\tif(this.componentAffectsComponentSystem(system, component)) {\n\t\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\tremoveEntityFromComponentSystem(entity: Entity<C>, component: keyof C) {\n\t\tthis.systems.forEach(system => {\n\t\t\tif(system instanceof EntitySystem && system.options.components?.includes(component)) {\n\t\t\t\tsystem.removeEntity(entity);\n\t\t\t} else if(system instanceof ComponentSystem) {\n\t\t\t\tif(this.componentAffectsComponentSystem(system, component)) {\n\t\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\tprivate componentAffectsComponentSystem(system: ComponentSystem<C>, component: keyof C): boolean {\n\t\tconst affectsMainQuery = system.options.required.includes(component)\n\t\t\t|| !!system.options.not?.includes(component)\n\t\t\t|| !!system.options.optional?.includes(component);\n\t\tconst affectsSubQuery = Object.values(system.options.queries ?? {}).some(query => {\n\t\t\treturn query.required.includes(component)\n\t\t\t\t|| !!query.not?.includes(component)\n\t\t\t\t|| !!query.optional?.includes(component);\n\t\t});\n\n\t\treturn affectsMainQuery || affectsSubQuery;\n\t}\n\n\tdestroy() {\n\t\tif(this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.systems.forEach(system => {\n\t\t\tsystem.destroy();\n\t\t});\n\t\tthis.destroyed = true;\n\t}\n}\n","import type ComponentWorkerMessage from './component-worker-message';\nimport type { ComponentMap } from '../../component-definition';\nimport type { ComponentSystemCallbacks, EntityUpdateComponents, EntityUpdateFunction, UpdateEntityConfigObject } from '../component-system';\n\n// Entry point a game's worker file calls with its update function. It wires up `self.onmessage`,\n// caches component blocks by entity id (so subsequent runs only need the id), and posts results back.\nexport default function createComponentWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>>(updateFunction: EntityUpdateFunction<C, T>) {\n\tconst cachedEntityComponent: { [key: number]: T } = {};\n\tconst cachedQueriesComponent: { [key: string]: { [key: number]: T } } = {};\n\n\tself.onmessage = function(e) {\n\t\tconst message = e.data as ComponentWorkerMessage;\n\n\t\tif(message.type === 'init') {\n\t\t\tpostMessageTyped({\n\t\t\t\ttype: 'loaded'\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\n\t\t\tlet queries: { [key: string]: Array<{ entityId: number, components: T }> } = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, entities]) => {\n\t\t\t\tlet cachedQueryComponent = cachedQueriesComponent[queryKey];\n\t\t\t\tif(!cachedQueryComponent) {\n\t\t\t\t\tcachedQueryComponent = cachedQueriesComponent[queryKey] = {};\n\t\t\t\t}\n\n\t\t\t\tqueries[queryKey] = entities.map(entity => {\n\t\t\t\t\tlet components, entityId;\n\t\t\t\t\tif(typeof entity === 'number') {\n\t\t\t\t\t\tcomponents = cachedQueryComponent[entity];\n\t\t\t\t\t\tentityId = entity;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcachedQueryComponent[entity.entityId] = components = entity.components as T;\n\t\t\t\t\t\tentityId = entity.entityId;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tcomponents\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tlet entities: Array<UpdateEntityConfigObject<T>> = [];\n\t\t\tfor(let entity of message.entities) {\n\t\t\t\tlet components, entityId;\n\t\t\t\tif(typeof entity === 'number') {\n\t\t\t\t\tcomponents = cachedEntityComponent[entity];\n\t\t\t\t\tentityId = entity;\n\t\t\t\t} else {\n\t\t\t\t\tcachedEntityComponent[entity.entityId] = components = entity.components as T;\n\t\t\t\t\tentityId = entity.entityId;\n\t\t\t\t}\n\n\t\t\t\tentities.push({\n\t\t\t\t\tentityId,\n\t\t\t\t\tcomponents\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet callbacks: ComponentSystemCallbacks<C> = {\n\t\t\t\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'component-property-updated',\n\t\t\t\t\t\targs: [componentName, prop, value]\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t};\n\t\t\tif(updateFunction.preRun) {\n\t\t\t\tupdateFunction.preRun(message.world, entities, queries, callbacks);\n\t\t\t}\n\n\t\t\tentities.forEach(entity => {\n\t\t\t\tupdateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t});\n\n\t\t\tmessage.removed.forEach(entityId => {\n\t\t\t\tdelete cachedEntityComponent[entityId];\n\t\t\t\tObject.values(cachedQueriesComponent).forEach(query => {\n\t\t\t\t\tdelete query[entityId];\n\t\t\t\t});\n\n\t\t\t\tif(updateFunction.entityRemoved) {\n\t\t\t\t\tupdateFunction.entityRemoved(message.world, entityId, callbacks);\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst runTime = performance.now() - start;\n\n\t\t\tpostMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction postMessageTyped(message: ComponentWorkerMessage) {\n\tself.postMessage(message);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/memory-component.ts","../src/entity.ts","../src/systems/system.ts","../src/systems/iterable-system.ts","../src/systems/entity-system.ts","../src/systems/workers/web-worker.ts","../src/systems/workers/component-web-worker.ts","../src/systems/component-system.ts","../src/world.ts","../src/systems/workers/create-component-worker.ts"],"sourcesContent":["import { LocalPool, type MemoryHeap, type TypedArrayConstructor } from '@daneren2005/shared-memory-objects';\n\n// The typed arrays a MemoryComponent can be backed by. Kept narrower than the package's TypedArray\n// union on purpose since these are the only types we allocate blocks of.\nexport type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;\n\n// A pool of same sized blocks living inside a shared MemoryHeap. Each component instance owns one\n// block (referenced by its index) so component data can be shared with worker threads.\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: LocalPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number) {\n\t\tthis.heap = heap;\n\t\tthis.pool = new LocalPool(heap, {\n\t\t\ttype,\n\t\t\tdataLength,\n\t\t});\n\t}\n\n\tget length() {\n\t\treturn this.pool.length;\n\t}\n\tget rawLength() {\n\t\treturn this.pool.bufferLength;\n\t}\n\n\tcreate(values: Array<number>): number {\n\t\treturn this.pool.push(values);\n\t}\n\n\tgetBlock(index: number): T {\n\t\treturn this.pool.at(index);\n\t}\n\tget(index: number, dataIndex: number): number {\n\t\treturn this.pool.get(index, dataIndex);\n\t}\n\tset(index: number, dataIndex: number, value: number) {\n\t\tlet array = this.pool.at(index);\n\t\tarray[dataIndex] = value;\n\t}\n\n\tdelete(index: number) {\n\t\tthis.pool.deleteIndex(index);\n\t}\n\tclear() {\n\t\tthis.pool.clear();\n\t}\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { ComponentMap } from './component-definition';\n\n// A bare entity: an id, an eid, and a bag of memory-backed components\nexport default class BaseEntity<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\tstatic eidCounter = 1;\n\n\t// eid is a fast numeric reference for internal lookups (worker threads, caches). id is the\n\t// stable string reference used by save data / cross-entity references.\n\treadonly eid: number;\n\tid?: string;\n\tconfig?: any;\n\n\tworld: BaseWorld<C>;\n\tcomponents: Partial<C> = {};\n\tdead = false;\n\tisStatic = false;\n\n\tconstructor(world: BaseWorld<C>, config?: any) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.eid = BaseEntity.eidCounter++;\n\t\tif(config) {\n\t\t\tthis.load(config);\n\t\t}\n\t}\n\n\tloadComponent<K extends keyof C>(name: K, config: any): C[K] {\n\t\tconst definition = this.world.registry[name];\n\t\tconst memoryComponent = this.world.components[name];\n\t\t// BaseEntity is invariant over C (registry/components), so widen to the definition's default BaseEntity.\n\t\tconst component = definition.load(this as unknown as BaseEntity, memoryComponent, config);\n\t\tthis.components[name] = component;\n\t\tthis.emit('component-added', name, component);\n\n\t\treturn component;\n\t}\n\tremoveComponent<K extends keyof C>(name: K) {\n\t\tconst component = this.components[name];\n\t\tif(component) {\n\t\t\tthis.world.components[name].delete(component.index);\n\t\t\tdelete this.components[name];\n\t\t\tthis.emit('component-removed', name);\n\t\t}\n\t}\n\tsetComponent<K extends keyof C, P extends keyof C[K]>(componentName: K, prop: P, value: C[K][P]) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\t// TS can't verify writing to a property of the generic C[K] by a keyof C[K] key, so index through a record.\n\t\t(component as unknown as Record<P, C[K][P]>)[prop] = value;\n\t\tthis.emit('component-property-updated', componentName, prop, value);\n\t}\n\t/**\n\t * NOTE: Does not emit component-property-updated!\n\t */\n\tsetComponentBulk<K extends keyof C>(componentName: K, values: Partial<C[K]>) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tObject.assign(component, values);\n\t}\n\tdeleteComponent<K extends keyof C>(componentName: K, prop: keyof C[K]) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tdelete (component as Partial<C[K]>)[prop];\n\t\tthis.emit('component-property-deleted', componentName, prop);\n\t}\n\n\tdeleteAllComponentMemory() {\n\t\tfor(let name of Object.keys(this.components) as Array<keyof C>) {\n\t\t\tconst component = this.components[name];\n\t\t\tif(component) {\n\t\t\t\tthis.world.components[name].delete(component.index);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Loads only component data: every key in the config that maps to a registered component is handed to that component's loader.\n\tload(config: any) {\n\t\tfor(let name in config) {\n\t\t\tif(name in this.world.registry) {\n\t\t\t\tthis.loadComponent(name, config[name]);\n\t\t\t}\n\t\t}\n\n\t\tthis.config = config;\n\t}\n\tsave() {\n\t\tconst config: { [key: string]: any } = {};\n\n\t\tfor(let name of Object.keys(this.components) as Array<keyof C>) {\n\t\t\tconst definition = this.world.registry[name];\n\t\t\tconst component = this.components[name];\n\t\t\tif(definition.save && component) {\n\t\t\t\tconfig[name as string] = definition.save(component);\n\t\t\t}\n\t\t}\n\n\t\treturn config;\n\t}\n\t// Hook for games that need a second pass once every entity in a load batch exists.\n\tfinishLoading() {}\n}\n","import type BaseWorld from '../world';\nimport type { ComponentMap } from '../component-definition';\n\n// Base system: runs on an optional fixed timestep (deltaBetweenRuns) and is driven by BaseWorld#update.\nexport default abstract class System<C extends ComponentMap = ComponentMap> {\n\tworld: BaseWorld<C>;\n\tname: string;\n\tcurrentDelta: number = 0;\n\tdeltaBetweenRuns: number;\n\tfirstRun: boolean;\n\n\tconstructor(world: BaseWorld<C>, options: SystemConfig = { name: 'System' }) {\n\t\tthis.name = options.name;\n\t\tthis.world = world;\n\n\t\tthis.deltaBetweenRuns = options.deltaBetweenRuns ?? 0;\n\t\tthis.firstRun = options.firstRun !== undefined ? options.firstRun : false;\n\t}\n\n\tinit(): void | Promise<void> {}\n\n\tclear() {\n\t\tthis.currentDelta = 0;\n\t}\n\tfinishLoading() {}\n\n\tupdate(elapsedTime: number): boolean {\n\t\tthis.currentDelta += elapsedTime;\n\n\t\tif(this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {\n\t\t\tlet leftOverDelta = 0;\n\t\t\tif(this.deltaBetweenRuns > 0) {\n\t\t\t\t// Without this if we take 100ms to run (ie: IterableSystem across multiple frames) then we will end up\n\t\t\t\t// actually running this in 300ms total instead of again in 100ms for a total of 200ms\n\t\t\t\t// With firstRun this ends up calling run(0) the first time - this makes it so things like events are\n\t\t\t\t// will trigger on the second instead of triggering a 1 second timer at 1.0166 seconds\n\t\t\t\tleftOverDelta = this.currentDelta % this.deltaBetweenRuns;\n\t\t\t}\n\n\t\t\tthis.run(this.currentDelta - leftOverDelta);\n\t\t\tthis.currentDelta = leftOverDelta;\n\t\t\tthis.firstRun = false;\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tabstract run(elapsedTime: number): void;\n\n\tshouldRun(): boolean {\n\t\treturn true;\n\t}\n\n\tdestroy() {}\n}\n\nexport interface SystemConfig {\n\tname: string\n\tdeltaBetweenRuns?: number\n\t// Defaults to false\n\tfirstRun?: boolean\n}\n","import type BaseWorld from '../world';\nimport type { ComponentMap } from '../component-definition';\nimport System, { type SystemConfig } from './system';\n\n// A system that iterates a list of instances, spreading the work across multiple frames if a single\n// pass would exceed maxMsPerFrame.\nexport default abstract class IterableSystem<C extends ComponentMap, T> extends System<C> {\n\tremainingInstancesToRun: Array<T> = [];\n\tremainingInstancesStartTime: number | null = null;\n\titerationsPerCheck: number;\n\tmaxMsPerFrame: number;\n\n\tconstructor(world: BaseWorld<C>, options: IterableSystemConfig) {\n\t\tsuper(world, options);\n\n\t\tthis.iterationsPerCheck = options.iterationsPerCheck ?? 1;\n\t\tthis.maxMsPerFrame = options.maxMsPerFrame ?? 10;\n\t}\n\n\tclear() {\n\t\tsuper.clear();\n\n\t\tthis.remainingInstancesToRun = [];\n\t\tthis.remainingInstancesStartTime = null;\n\t}\n\n\tupdate(elapsedTime: number): boolean {\n\t\tif(this.remainingInstancesToRun.length) {\n\t\t\tthis.runIterables(this.remainingInstancesToRun, this.remainingInstancesStartTime ?? 0);\n\t\t\tthis.currentDelta += elapsedTime;\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn super.update(elapsedTime);\n\t\t}\n\t}\n\trun(elapsedTime: number): void {\n\t\tlet iterables = this.getIterables();\n\t\tthis.runIterables(iterables, elapsedTime);\n\t}\n\trunIterables(iterables: Array<T>, elapsedTime: number) {\n\t\tlet started = performance.now();\n\t\tthis.beforeRunIterables();\n\t\tfor(let i = 0; i < iterables.length; i++) {\n\t\t\tthis.updateIterable(iterables[i], elapsedTime);\n\n\t\t\tif(i % this.iterationsPerCheck === 0) {\n\t\t\t\tlet now = performance.now();\n\t\t\t\tif(now - started >= this.maxMsPerFrame) {\n\t\t\t\t\tthis.remainingInstancesToRun = iterables.slice(i + 1);\n\t\t\t\t\tthis.remainingInstancesStartTime = elapsedTime;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.remainingInstancesToRun = [];\n\t\tthis.remainingInstancesStartTime = null;\n\t}\n\tbeforeRunIterables() {}\n\n\tabstract getIterables(): Array<T>;\n\tabstract updateIterable(iterable: T, elapsedTime: number): void;\n}\n\nexport interface IterableSystemConfig extends SystemConfig {\n\titerationsPerCheck?: number\n\tmaxMsPerFrame?: number\n}\n","import type BaseWorld from '../world';\nimport type BaseEntity from '../entity';\nimport type { ComponentMap } from '../component-definition';\nimport IterableSystem, { type IterableSystemConfig } from './iterable-system';\n\n// Iterates the entities that own a given set of components on the main thread. Entities are added\n// and removed automatically as the world emits entity-added / entity-removed / component changes.\nexport default abstract class EntitySystem<C extends ComponentMap, T extends BaseEntity<C> = BaseEntity<C>> extends IterableSystem<C, T> {\n\tentities: Array<T> = [];\n\toptions: EntitySystemConfig<C>;\n\n\tconstructor(world: BaseWorld<C>, options: EntitySystemConfig<C> = { name: 'EntitySystem' }) {\n\t\tif(!options.iterationsPerCheck) {\n\t\t\toptions.iterationsPerCheck = 10;\n\t\t}\n\t\tif(!options.maxMsPerFrame) {\n\t\t\toptions.maxMsPerFrame = 4;\n\t\t}\n\n\t\tsuper(world, options);\n\t\tthis.options = options;\n\n\t\tworld.on('entity-added', (entity: BaseEntity<C>) => {\n\t\t\tif(this.checkAddEntity(entity) && this.options.updateEntityOnAdd) {\n\t\t\t\tthis.updateEntity(entity as T, 0);\n\t\t\t}\n\t\t});\n\t\tworld.on('entity-removed', (entity: BaseEntity<C>) => {\n\t\t\tthis.removeEntity(entity);\n\t\t});\n\n\t\tworld.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t}\n\n\tgetIterables(): Array<T> {\n\t\treturn this.entities.filter(entity => !entity.dead);\n\t}\n\tupdateIterable(entity: T, elapsedTime: number): void {\n\t\tif(entity.dead) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateEntity(entity, elapsedTime);\n\t}\n\tfilterEntity(entity: BaseEntity<C>): boolean {\n\t\treturn !entity.isStatic;\n\t}\n\tisEntityInSystem(entity: BaseEntity<C>) {\n\t\treturn this.entities.indexOf(entity as T) !== -1;\n\t}\n\tabstract updateEntity(entity: T, elapsedTime: number): void;\n\n\tcheckAddEntity(entity: BaseEntity<C>): boolean {\n\t\tif(this.options.components && this.options.components.filter(component => !!entity.components[component]).length !== this.options.components.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(this.filterEntity(entity)) {\n\t\t\tthis.entities.push(entity as T);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tremoveEntity(entity: BaseEntity<C>) {\n\t\tlet index = this.entities.indexOf(entity as T);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t}\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.length > 0;\n\t}\n}\n\nexport interface EntitySystemConfig<C extends ComponentMap> extends IterableSystemConfig {\n\tcomponents?: Array<keyof C>\n\tupdateEntityOnAdd?: boolean\n}\n","// Minimal Worker-like base used for the main-thread fallback when real Web Workers / SharedArrayBuffer\n// are unavailable. Params are intentionally loose since this is the (serialization) boundary that\n// mirrors the DOM Worker interface.\nexport default abstract class WebWorker {\n\tabstract postMessage(message: any): void | Promise<void>;\n\tonmessage(message: any, transferrables: Array<any> = []): void {\n\n\t}\n}\n","import WebWorker from './web-worker';\nimport type ComponentWorkerMessage from './component-worker-message';\nimport type { ComponentMap } from '../../component-definition';\nimport type { ComponentSystemCallbacks, EntityQueryComponents, EntityUpdateComponents, EntityUpdateFunction, UpdateEntityConfigObject } from '../component-system';\n\n// Main-thread fallback that runs the update function synchronously when real Web Workers /\n// SharedArrayBuffer are unavailable. Because it runs in-process it can pass the components straight\n// through without caching them by entity id.\nexport default class ComponentWebWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>> extends WebWorker {\n\tprivate updateFunction: EntityUpdateFunction<C, T>;\n\n\tconstructor(updateFunction: EntityUpdateFunction<C, T>) {\n\t\tsuper();\n\t\tthis.updateFunction = updateFunction;\n\t}\n\n\tpostMessage(message: ComponentWorkerMessage): void {\n\t\tif(message.type === 'init') {\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\n\t\t\tlet callbacks: ComponentSystemCallbacks<C> = {\n\t\t\t\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'component-property-updated',\n\t\t\t\t\t\targs: [componentName, prop, value],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t};\n\t\t\tif(this.updateFunction.preRun) {\n\t\t\t\tthis.updateFunction.preRun(message.world, message.entities as Array<UpdateEntityConfigObject<T>>, message.queries as EntityQueryComponents<C>, callbacks);\n\t\t\t}\n\t\t\tmessage.entities.forEach(entity => {\n\t\t\t\t// Should not be called\n\t\t\t\tif(typeof entity === 'number') {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.updateFunction(message.world, entity.entityId, entity.components as T, message.queries as EntityQueryComponents<C>, callbacks);\n\t\t\t});\n\n\t\t\tif(this.updateFunction.entityRemoved) {\n\t\t\t\tfor(let entityId of message.removed) {\n\t\t\t\t\tthis.updateFunction.entityRemoved(message.world, entityId, callbacks);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime: 0,\n\t\t\t\tevents: entityEvents,\n\t\t\t});\n\t\t}\n\t}\n\n\tonMessageTyped(message: ComponentWorkerMessage) {\n\t\tthis.onmessage({\n\t\t\tdata: message,\n\t\t});\n\t}\n}\n","import type BaseWorld from '../world';\nimport type BaseEntity from '../entity';\nimport type { BaseComponent, ComponentMap } from '../component-definition';\nimport type { ComponentTypedArray } from '../memory-component';\nimport System, { type SystemConfig } from './system';\nimport type ComponentWorkerMessage from './workers/component-worker-message';\nimport ComponentWebWorker from './workers/component-web-worker';\n\nconst MAIN_QUERY_NAME = '___main';\n\n// Runs an update function over the raw shared-memory blocks of its matched entities, ideally on a\n// separate thread. When Web Workers + SharedArrayBuffer are available the work happens on `getWorker()`;\n// otherwise it falls back to running synchronously on the main thread via ComponentWebWorker.\n//\n// This is deliberately free of any game concepts (no factions, fog of war, position, etc). Games\n// inject whatever extra per-run data they need through `addDataToWorld`.\nexport default abstract class ComponentSystem<C extends ComponentMap = ComponentMap, T extends EntityUpdateComponents<C> = EntityUpdateComponents<C>> extends System<C> {\n\tentities: Array<BaseEntity<C>> = [];\n\toptions: ComponentSystemConfig<C, T>;\n\n\tworker: Worker | ComponentWebWorker<C, T>;\n\tisWorkerThread: boolean;\n\n\tprivate loaded = false;\n\tprivate loadingPromise: { promise: Promise<void>, resolve: (value: void | PromiseLike<void>) => void } | null = null;\n\tprivate isRunning = false;\n\tprivate queryEntityComponentCache: { [key: string]: { [key: number]: { entity: BaseEntity<C>, components: T } } } = {};\n\tprivate queryEntities: { [key: string]: Array<BaseEntity<C>> } = {};\n\tprivate removedEntityBuffer: Array<number> = [];\n\n\t// Optional hook for subclasses to attach extra data to the world object sent to the worker.\n\taddDataToWorld?(world: ComponentSystemWorld): void;\n\n\tconstructor(world: BaseWorld<C>, options: ComponentSystemConfig<C, T>) {\n\t\tsuper(world, options);\n\t\tthis.options = options;\n\t\tObject.keys(this.options.queries ?? {}).forEach(queryName => {\n\t\t\tthis.queryEntities[queryName] = [];\n\t\t});\n\n\t\tworld.on('entity-added', (entity: BaseEntity<C>) => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t\tworld.on('entity-removed', (entity: BaseEntity<C>) => {\n\t\t\tthis.removeEntity(entity);\n\t\t});\n\n\t\tworld.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\n\t\tif(!options.forceMainThread && typeof globalThis.Worker !== 'undefined' && typeof globalThis.SharedArrayBuffer !== 'undefined') {\n\t\t\tthis.worker = options.getWorker();\n\t\t\tthis.isWorkerThread = true;\n\t\t} else {\n\t\t\tthis.worker = new ComponentWebWorker(options.updateFunction);\n\t\t\tthis.isWorkerThread = false;\n\t\t}\n\n\t\tthis.initWorker();\n\t}\n\n\tprivate initWorker() {\n\t\tthis.worker.onmessage = (e: MessageEvent) => {\n\t\t\tlet message = e.data as ComponentWorkerMessage;\n\t\t\tif(message.type === 'loaded') {\n\t\t\t\tthis.loaded = true;\n\t\t\t\tif(this.loadingPromise) {\n\t\t\t\t\tthis.loadingPromise.resolve();\n\t\t\t\t\tthis.loadingPromise = null;\n\t\t\t\t}\n\t\t\t} else if(message.type === 'run-complete') {\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tif(this.isWorkerThread) {\n\t\t\t\t\tthis.world.emit(`system-${this.name}-worker-finished`, message.runTime);\n\t\t\t\t}\n\n\t\t\t\tmessage.events.forEach(event => {\n\t\t\t\t\tconst entity = this.queryEntityComponentCache[MAIN_QUERY_NAME][event.entityId]?.entity ?? this.entities.find(entity => entity.eid === event.entityId);\n\t\t\t\t\tif(!entity) {\n\t\t\t\t\t\tconsole.warn(`Could not find entity with id ${event.entityId}`);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tentity.emit(event.event, ...event.args);\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage = {\n\t\t\ttype: 'init',\n\t\t};\n\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tinit(): Promise<void> | void {\n\t\tif(this.loaded) {\n\t\t\treturn;\n\t\t} else if(this.loadingPromise) {\n\t\t\treturn this.loadingPromise.promise;\n\t\t}\n\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\tthis.loadingPromise = {\n\t\t\tpromise,\n\t\t\tresolve,\n\t\t};\n\t\treturn promise;\n\t}\n\n\tupdate(elapsedTime: number): boolean {\n\t\t// Only run worker if the last run completed already\n\t\tif(this.isRunning) {\n\t\t\tthis.currentDelta += elapsedTime;\n\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn super.update(elapsedTime);\n\t\t}\n\t}\n\trun(elapsedTime: number): void {\n\t\tconst world: ComponentSystemWorld = {\n\t\t\tgameTime: this.world.gameTime,\n\t\t\telapsedTime,\n\t\t};\n\t\tthis.addDataToWorld?.(world);\n\n\t\tthis.isRunning = true;\n\t\tlet entities = this.runQuery(MAIN_QUERY_NAME, this.entities, this.options);\n\t\tlet queries: { [key: string]: Array<UpdateEntityConfig<T>> } = {};\n\t\tObject.entries(this.options.queries ?? {}).forEach(([queryKey, query]) => {\n\t\t\tqueries[queryKey] = this.runQuery(queryKey, this.queryEntities[queryKey] ?? [], query);\n\t\t});\n\t\tlet message: ComponentWorkerMessage = {\n\t\t\ttype: 'run',\n\t\t\tworld,\n\t\t\tentities,\n\t\t\tqueries,\n\t\t\tremoved: this.removedEntityBuffer,\n\t\t};\n\t\tthis.worker.postMessage(message);\n\t\tthis.removedEntityBuffer = [];\n\t}\n\n\trunQuery(queryName: string, entities: Array<BaseEntity<C>>, query: ComponentSystemQuery<C>): Array<UpdateEntityConfig<T>> {\n\t\tlet filteredEntities: Array<UpdateEntityConfig<T>> = [];\n\n\t\tlet cache = this.queryEntityComponentCache[queryName];\n\t\tif(!cache) {\n\t\t\tcache = this.queryEntityComponentCache[queryName] = {};\n\t\t}\n\t\tentities.forEach(entity => {\n\t\t\tif(entity.dead) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet components = cache[entity.eid]?.components;\n\t\t\t// Cache components memory since doing the lookup is kind of slow\n\t\t\tif(!components) {\n\t\t\t\tcomponents = {} as T;\n\t\t\t\t[\n\t\t\t\t\t...query.required,\n\t\t\t\t\t...query.optional ?? [],\n\t\t\t\t].forEach(componentName => {\n\t\t\t\t\tconst component = entity.components[componentName];\n\t\t\t\t\tconst memoryComponent = this.world.components[componentName];\n\t\t\t\t\tif(component && memoryComponent) {\n\t\t\t\t\t\tcomponents[componentName] = memoryComponent.getBlock(component.index) as T[typeof componentName];\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tcache[entity.eid] = {\n\t\t\t\t\tentity,\n\t\t\t\t\tcomponents,\n\t\t\t\t};\n\n\t\t\t\tfilteredEntities.push({\n\t\t\t\t\tentityId: entity.eid,\n\t\t\t\t\tcomponents,\n\t\t\t\t});\n\t\t\t} else if(this.isWorkerThread) {\n\t\t\t\t// For worker threads it is slow to send the components in postMessage - so thread caches them after first time sent\n\t\t\t\tfilteredEntities.push(entity.eid);\n\t\t\t} else {\n\t\t\t\t// For main thread execution it is faster to just pass the components to be used directly\n\t\t\t\tfilteredEntities.push({\n\t\t\t\t\tentityId: entity.eid,\n\t\t\t\t\tcomponents,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\treturn filteredEntities;\n\t}\n\n\tisEntityInSystem(entity: BaseEntity<C>) {\n\t\treturn this.entities.indexOf(entity) !== -1;\n\t}\n\tprivate matchesQuery(entity: BaseEntity<C>, query: ComponentSystemQuery<C>): boolean {\n\t\tif(entity.dead) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(query.required.find(component => !entity.components[component])) {\n\t\t\treturn false;\n\t\t}\n\t\tif(query.not?.find(component => !!entity.components[component])) {\n\t\t\treturn false;\n\t\t}\n\t\tif(query.filter && !query.filter(entity)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\tprivate updateEntityList(list: Array<BaseEntity<C>>, entity: BaseEntity<C>, shouldInclude: boolean) {\n\t\tlet index = list.indexOf(entity);\n\t\tif(shouldInclude) {\n\t\t\tif(index === -1) {\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t} else if(index !== -1) {\n\t\t\tlist.splice(index, 1);\n\t\t}\n\t}\n\n\tcheckAddEntity(entity: BaseEntity<C>): boolean {\n\t\tconst shouldAddToMain = this.matchesQuery(entity, this.options);\n\t\tthis.updateEntityList(this.entities, entity, shouldAddToMain);\n\n\t\tObject.entries(this.options.queries ?? {}).forEach(([queryName, query]) => {\n\t\t\tconst queryList = this.queryEntities[queryName] ?? (this.queryEntities[queryName] = []);\n\t\t\tthis.updateEntityList(queryList, entity, this.matchesQuery(entity, query));\n\t\t});\n\n\t\t// Invalidate cached components so they are rebuilt with current components on next runQuery\n\t\tObject.values(this.queryEntityComponentCache).forEach(cache => {\n\t\t\tif(cache[entity.eid]) {\n\t\t\t\tdelete cache[entity.eid];\n\t\t\t}\n\t\t});\n\n\t\treturn shouldAddToMain;\n\t}\n\tremoveEntity(entity: BaseEntity<C>) {\n\t\tthis.updateEntityList(this.entities, entity, false);\n\t\tObject.values(this.queryEntities).forEach(list => {\n\t\t\tthis.updateEntityList(list, entity, false);\n\t\t});\n\n\t\tObject.values(this.queryEntityComponentCache).forEach(cache => {\n\t\t\tif(cache[entity.eid]) {\n\t\t\t\tdelete cache[entity.eid];\n\t\t\t}\n\t\t});\n\t\tthis.removedEntityBuffer.push(entity.eid);\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.length > 0;\n\t}\n\n\tdestroy() {\n\t\tif('terminate' in this.worker) {\n\t\t\tthis.worker.terminate();\n\t\t}\n\t}\n}\n\nexport type EntityUpdateComponents<C extends ComponentMap = ComponentMap> = { [K in keyof C]?: ComponentTypedArray };\nexport type EntityQueryComponents<C extends ComponentMap = ComponentMap> = { [key: string]: Array<{ entityId: number, components: EntityUpdateComponents<C> }> };\ntype EntityUpdateFunctionImpl<C extends ComponentMap, T extends EntityUpdateComponents<C>> = (\n\tworld: ComponentSystemWorld,\n\tentityId: number,\n\tcomponents: T,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\nexport type EntityUpdateFunction<C extends ComponentMap, T extends EntityUpdateComponents<C> = EntityUpdateComponents<C>> = EntityUpdateFunctionImpl<C, T> & {\n\tpreRun?: EntityUpdatePreRunFunction<C, T>\n\tentityRemoved?: EntityRemovedFunction<C>\n};\nexport type EntityUpdatePreRunFunction<C extends ComponentMap, T extends EntityUpdateComponents<C>> = (\n\tworld: ComponentSystemWorld,\n\tentities: Array<UpdateEntityConfigObject<T>>,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\nexport type EntityRemovedFunction<C extends ComponentMap = ComponentMap> = (world: ComponentSystemWorld, entityId: number, callbacks: ComponentSystemCallbacks<C>) => void;\nexport type UpdateEntityConfig<T extends EntityUpdateComponents = EntityUpdateComponents> = number | UpdateEntityConfigObject<T>;\nexport type UpdateEntityConfigObject<T extends EntityUpdateComponents> = {\n\tentityId: number\n\tcomponents: T\n};\n\n// Base per-run world data. gameTime + elapsedTime are always present; games attach anything else\n// they need via addDataToWorld, which is why an index signature is included.\nexport interface ComponentSystemWorld {\n\tgameTime: number\n\telapsedTime: number\n\t[key: string]: unknown\n}\nexport interface ComponentSystemCallbacks<C extends ComponentMap = ComponentMap> {\n\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]): void\n}\n\nexport interface ComponentSystemQuery<C extends ComponentMap = ComponentMap> {\n\trequired: Array<keyof C>\n\toptional?: Array<keyof C>\n\tnot?: Array<keyof C>\n\tfilter?: (entity: BaseEntity<C>) => boolean\n}\n\nexport interface ComponentSystemConfig<C extends ComponentMap, T extends EntityUpdateComponents<C>> extends SystemConfig, ComponentSystemQuery<C> {\n\tupdateFunction: EntityUpdateFunction<C, T>\n\tgetWorker: () => Worker\n\tforceMainThread?: boolean\n\n\tqueries?: { [key: string]: ComponentSystemQuery<C> }\n}\n\n// Re-exported so BaseComponent is reachable from the systems barrel if needed.\nexport type { BaseComponent };\n","import { EventEmitter } from 'eventemitter3';\nimport { MAX_BYTE_OFFSET_LENGTH, MemoryHeap } from '@daneren2005/shared-memory-objects';\nimport MemoryComponent from './memory-component';\nimport BaseEntity from './entity';\nimport type System from './systems/system';\nimport EntitySystem from './systems/entity-system';\nimport ComponentSystem from './systems/component-system';\nimport type { ComponentMap, ComponentRegistry } from './component-definition';\n\nconst DEFAULT_HEAP_SIZE = MAX_BYTE_OFFSET_LENGTH;\n\nexport interface WorldOptions {\n\theapSize?: number\n}\n\n// A simple wrapper around a set of entities + systems. On construction it creates one\n// MemoryComponent per entry in the component registry so entities can load/save themselves without\n// each game re-declaring loaders/savers. It has no game specific load/save/terrain/faction logic -\n// that all belongs in the game that consumes this library.\nexport default class BaseWorld<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\theap: MemoryHeap;\n\tregistry: ComponentRegistry<C>;\n\tcomponents: { [K in keyof C]: MemoryComponent };\n\n\tentities: Array<BaseEntity<C>> = [];\n\tentitiesByEid: { [eid: number]: BaseEntity<C> } = {};\n\tsystems: Array<System<C>> = [];\n\n\tgameTime = 0;\n\tdestroyed = false;\n\n\tconstructor(registry: ComponentRegistry<C>, options: WorldOptions = {}) {\n\t\tsuper();\n\n\t\tthis.registry = registry;\n\t\tthis.heap = new MemoryHeap({ bufferSize: options.heapSize ?? DEFAULT_HEAP_SIZE });\n\n\t\tconst components = {} as { [K in keyof C]: MemoryComponent };\n\t\tfor(let name of Object.keys(registry) as Array<keyof C>) {\n\t\t\tconst definition = registry[name];\n\t\t\tcomponents[name] = new MemoryComponent(this.heap, definition.type, definition.size);\n\t\t}\n\t\tthis.components = components;\n\t}\n\n\tasync init() {\n\t\tawait Promise.all(this.systems.map(system => system.init()).filter(promise => promise instanceof Promise));\n\t}\n\n\taddEntity(entity: BaseEntity<C>, created = true): BaseEntity<C> {\n\t\tthis.entities.push(entity);\n\t\tthis.entitiesByEid[entity.eid] = entity;\n\t\tentity.world = this;\n\n\t\tentity.on('component-added', (name: keyof C) => {\n\t\t\tthis.addEntityToComponentSystem(entity, name);\n\t\t});\n\t\tentity.on('component-removed', (name: keyof C) => {\n\t\t\tthis.removeEntityFromComponentSystem(entity, name);\n\t\t});\n\n\t\tif(created) {\n\t\t\tentity.finishLoading();\n\t\t}\n\t\tthis.emit('entity-added', entity);\n\n\t\treturn entity;\n\t}\n\tloadEntity(config: any, created = true): BaseEntity<C> {\n\t\treturn this.addEntity(new BaseEntity<C>(this, config), created);\n\t}\n\tremoveEntity(entity: BaseEntity<C>) {\n\t\tlet index = this.entities.indexOf(entity);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t\tdelete this.entitiesByEid[entity.eid];\n\t\t\tthis.emit('entity-removed', entity);\n\t\t}\n\n\t\tentity.deleteAllComponentMemory();\n\t}\n\tgetEntityByEid(eid: number): BaseEntity<C> | undefined {\n\t\treturn this.entitiesByEid[eid];\n\t}\n\n\taddSystem<T extends System<C>>(system: T): T {\n\t\tthis.systems.push(system);\n\t\treturn system;\n\t}\n\taddSystemIfNotExists(system: System<C>) {\n\t\tlet index = this.systems.findIndex(otherSystem => system.name === otherSystem.name);\n\t\tif(index === -1) {\n\t\t\tthis.systems.push(system);\n\t\t}\n\t}\n\tremoveSystem(name: string) {\n\t\tlet index = this.systems.findIndex(system => system.name === name);\n\t\tif(index !== -1) {\n\t\t\tthis.systems.splice(index, 1);\n\t\t}\n\t}\n\n\tupdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\tthis.gameTime += elapsedTime;\n\n\t\tlet lastSystemError: Error | null = null;\n\t\tthis.systems.forEach(system => {\n\t\t\tlet shouldRun = true;\n\t\t\tlet ran = false;\n\t\t\tlet failed = false;\n\t\t\tthis.emit(`system-${system.name}-started`);\n\t\t\ttry {\n\t\t\t\tshouldRun = system.shouldRun();\n\t\t\t\tif(shouldRun) {\n\t\t\t\t\tran = system.update(elapsedTime);\n\t\t\t\t}\n\t\t\t} catch(e) {\n\t\t\t\tconst error = e as Error;\n\t\t\t\tconsole.error(error.message, error);\n\t\t\t\tfailed = true;\n\t\t\t\tlastSystemError = error;\n\t\t\t}\n\t\t\tthis.emit(`system-${system.name}-finished`, {\n\t\t\t\tran,\n\t\t\t\tshouldRun,\n\t\t\t\tfailed,\n\t\t\t});\n\t\t});\n\n\t\treturn {\n\t\t\tlastSystemError,\n\t\t};\n\t}\n\n\taddEntityToComponentSystem(entity: BaseEntity<C>, component: keyof C) {\n\t\tthis.systems.forEach(system => {\n\t\t\tif(system instanceof EntitySystem && system.options.components?.includes(component)) {\n\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t} else if(system instanceof ComponentSystem) {\n\t\t\t\tif(this.componentAffectsComponentSystem(system, component)) {\n\t\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\tremoveEntityFromComponentSystem(entity: BaseEntity<C>, component: keyof C) {\n\t\tthis.systems.forEach(system => {\n\t\t\tif(system instanceof EntitySystem && system.options.components?.includes(component)) {\n\t\t\t\tsystem.removeEntity(entity);\n\t\t\t} else if(system instanceof ComponentSystem) {\n\t\t\t\tif(this.componentAffectsComponentSystem(system, component)) {\n\t\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\tprivate componentAffectsComponentSystem(system: ComponentSystem<C>, component: keyof C): boolean {\n\t\tconst affectsMainQuery = system.options.required.includes(component)\n\t\t\t|| !!system.options.not?.includes(component)\n\t\t\t|| !!system.options.optional?.includes(component);\n\t\tconst affectsSubQuery = Object.values(system.options.queries ?? {}).some(query => {\n\t\t\treturn query.required.includes(component)\n\t\t\t\t|| !!query.not?.includes(component)\n\t\t\t\t|| !!query.optional?.includes(component);\n\t\t});\n\n\t\treturn affectsMainQuery || affectsSubQuery;\n\t}\n\n\tdestroy() {\n\t\tif(this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.systems.forEach(system => {\n\t\t\tsystem.destroy();\n\t\t});\n\t\tthis.destroyed = true;\n\t}\n}\n","import type ComponentWorkerMessage from './component-worker-message';\nimport type { ComponentMap } from '../../component-definition';\nimport type { ComponentSystemCallbacks, EntityUpdateComponents, EntityUpdateFunction, UpdateEntityConfigObject } from '../component-system';\n\n// Entry point a game's worker file calls with its update function. It wires up `self.onmessage`,\n// caches component blocks by entity id (so subsequent runs only need the id), and posts results back.\nexport default function createComponentWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>>(updateFunction: EntityUpdateFunction<C, T>) {\n\tconst cachedEntityComponent: { [key: number]: T } = {};\n\tconst cachedQueriesComponent: { [key: string]: { [key: number]: T } } = {};\n\n\tself.onmessage = function(e) {\n\t\tconst message = e.data as ComponentWorkerMessage;\n\n\t\tif(message.type === 'init') {\n\t\t\tpostMessageTyped({\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\n\t\t\tlet queries: { [key: string]: Array<{ entityId: number, components: T }> } = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, entities]) => {\n\t\t\t\tlet cachedQueryComponent = cachedQueriesComponent[queryKey];\n\t\t\t\tif(!cachedQueryComponent) {\n\t\t\t\t\tcachedQueryComponent = cachedQueriesComponent[queryKey] = {};\n\t\t\t\t}\n\n\t\t\t\tqueries[queryKey] = entities.map(entity => {\n\t\t\t\t\tlet components, entityId;\n\t\t\t\t\tif(typeof entity === 'number') {\n\t\t\t\t\t\tcomponents = cachedQueryComponent[entity];\n\t\t\t\t\t\tentityId = entity;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcachedQueryComponent[entity.entityId] = components = entity.components as T;\n\t\t\t\t\t\tentityId = entity.entityId;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tcomponents,\n\t\t\t\t\t};\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tlet entities: Array<UpdateEntityConfigObject<T>> = [];\n\t\t\tfor(let entity of message.entities) {\n\t\t\t\tlet components, entityId;\n\t\t\t\tif(typeof entity === 'number') {\n\t\t\t\t\tcomponents = cachedEntityComponent[entity];\n\t\t\t\t\tentityId = entity;\n\t\t\t\t} else {\n\t\t\t\t\tcachedEntityComponent[entity.entityId] = components = entity.components as T;\n\t\t\t\t\tentityId = entity.entityId;\n\t\t\t\t}\n\n\t\t\t\tentities.push({\n\t\t\t\t\tentityId,\n\t\t\t\t\tcomponents,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet callbacks: ComponentSystemCallbacks<C> = {\n\t\t\t\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'component-property-updated',\n\t\t\t\t\t\targs: [componentName, prop, value],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t};\n\t\t\tif(updateFunction.preRun) {\n\t\t\t\tupdateFunction.preRun(message.world, entities, queries, callbacks);\n\t\t\t}\n\n\t\t\tentities.forEach(entity => {\n\t\t\t\tupdateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t});\n\n\t\t\tmessage.removed.forEach(entityId => {\n\t\t\t\tdelete cachedEntityComponent[entityId];\n\t\t\t\tObject.values(cachedQueriesComponent).forEach(query => {\n\t\t\t\t\tdelete query[entityId];\n\t\t\t\t});\n\n\t\t\t\tif(updateFunction.entityRemoved) {\n\t\t\t\t\tupdateFunction.entityRemoved(message.world, entityId, callbacks);\n\t\t\t\t}\n\t\t\t});\n\t\t\tconst runTime = performance.now() - start;\n\n\t\t\tpostMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction postMessageTyped(message: ComponentWorkerMessage) {\n\tself.postMessage(message);\n}\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
- import type World from '../world';
2
- import type Entity from '../entity';
1
+ import type BaseWorld from '../world';
2
+ import type BaseEntity from '../entity';
3
3
  import type { BaseComponent, ComponentMap } from '../component-definition';
4
4
  import type { ComponentTypedArray } from '../memory-component';
5
5
  import System, { type SystemConfig } from './system';
6
6
  import ComponentWebWorker from './workers/component-web-worker';
7
7
  export default abstract class ComponentSystem<C extends ComponentMap = ComponentMap, T extends EntityUpdateComponents<C> = EntityUpdateComponents<C>> extends System<C> {
8
- entities: Array<Entity<C>>;
8
+ entities: Array<BaseEntity<C>>;
9
9
  options: ComponentSystemConfig<C, T>;
10
10
  worker: Worker | ComponentWebWorker<C, T>;
11
11
  isWorkerThread: boolean;
@@ -16,17 +16,17 @@ export default abstract class ComponentSystem<C extends ComponentMap = Component
16
16
  private queryEntities;
17
17
  private removedEntityBuffer;
18
18
  addDataToWorld?(world: ComponentSystemWorld): void;
19
- constructor(world: World<C>, options: ComponentSystemConfig<C, T>);
19
+ constructor(world: BaseWorld<C>, options: ComponentSystemConfig<C, T>);
20
20
  private initWorker;
21
21
  init(): Promise<void> | void;
22
22
  update(elapsedTime: number): boolean;
23
23
  run(elapsedTime: number): void;
24
- runQuery(queryName: string, entities: Array<Entity<C>>, query: ComponentSystemQuery<C>): Array<UpdateEntityConfig<T>>;
25
- isEntityInSystem(entity: Entity<C>): boolean;
24
+ runQuery(queryName: string, entities: Array<BaseEntity<C>>, query: ComponentSystemQuery<C>): Array<UpdateEntityConfig<T>>;
25
+ isEntityInSystem(entity: BaseEntity<C>): boolean;
26
26
  private matchesQuery;
27
27
  private updateEntityList;
28
- checkAddEntity(entity: Entity<C>): boolean;
29
- removeEntity(entity: Entity<C>): void;
28
+ checkAddEntity(entity: BaseEntity<C>): boolean;
29
+ removeEntity(entity: BaseEntity<C>): void;
30
30
  shouldRun(): boolean;
31
31
  destroy(): void;
32
32
  }
@@ -63,7 +63,7 @@ export interface ComponentSystemQuery<C extends ComponentMap = ComponentMap> {
63
63
  required: Array<keyof C>;
64
64
  optional?: Array<keyof C>;
65
65
  not?: Array<keyof C>;
66
- filter?: (entity: Entity<C>) => boolean;
66
+ filter?: (entity: BaseEntity<C>) => boolean;
67
67
  }
68
68
  export interface ComponentSystemConfig<C extends ComponentMap, T extends EntityUpdateComponents<C>> extends SystemConfig, ComponentSystemQuery<C> {
69
69
  updateFunction: EntityUpdateFunction<C, T>;
@@ -1,18 +1,18 @@
1
- import type World from '../world';
2
- import type Entity from '../entity';
1
+ import type BaseWorld from '../world';
2
+ import type BaseEntity from '../entity';
3
3
  import type { ComponentMap } from '../component-definition';
4
4
  import IterableSystem, { type IterableSystemConfig } from './iterable-system';
5
- export default abstract class EntitySystem<C extends ComponentMap, T extends Entity<C> = Entity<C>> extends IterableSystem<C, T> {
5
+ export default abstract class EntitySystem<C extends ComponentMap, T extends BaseEntity<C> = BaseEntity<C>> extends IterableSystem<C, T> {
6
6
  entities: Array<T>;
7
7
  options: EntitySystemConfig<C>;
8
- constructor(world: World<C>, options?: EntitySystemConfig<C>);
8
+ constructor(world: BaseWorld<C>, options?: EntitySystemConfig<C>);
9
9
  getIterables(): Array<T>;
10
10
  updateIterable(entity: T, elapsedTime: number): void;
11
- filterEntity(entity: Entity<C>): boolean;
12
- isEntityInSystem(entity: Entity<C>): boolean;
11
+ filterEntity(entity: BaseEntity<C>): boolean;
12
+ isEntityInSystem(entity: BaseEntity<C>): boolean;
13
13
  abstract updateEntity(entity: T, elapsedTime: number): void;
14
- checkAddEntity(entity: Entity<C>): boolean;
15
- removeEntity(entity: Entity<C>): void;
14
+ checkAddEntity(entity: BaseEntity<C>): boolean;
15
+ removeEntity(entity: BaseEntity<C>): void;
16
16
  shouldRun(): boolean;
17
17
  }
18
18
  export interface EntitySystemConfig<C extends ComponentMap> extends IterableSystemConfig {
@@ -1,4 +1,4 @@
1
- import type World from '../world';
1
+ import type BaseWorld from '../world';
2
2
  import type { ComponentMap } from '../component-definition';
3
3
  import System, { type SystemConfig } from './system';
4
4
  export default abstract class IterableSystem<C extends ComponentMap, T> extends System<C> {
@@ -6,7 +6,7 @@ export default abstract class IterableSystem<C extends ComponentMap, T> extends
6
6
  remainingInstancesStartTime: number | null;
7
7
  iterationsPerCheck: number;
8
8
  maxMsPerFrame: number;
9
- constructor(world: World<C>, options: IterableSystemConfig);
9
+ constructor(world: BaseWorld<C>, options: IterableSystemConfig);
10
10
  clear(): void;
11
11
  update(elapsedTime: number): boolean;
12
12
  run(elapsedTime: number): void;
@@ -1,12 +1,12 @@
1
- import type World from '../world';
1
+ import type BaseWorld from '../world';
2
2
  import type { ComponentMap } from '../component-definition';
3
3
  export default abstract class System<C extends ComponentMap = ComponentMap> {
4
- world: World<C>;
4
+ world: BaseWorld<C>;
5
5
  name: string;
6
6
  currentDelta: number;
7
7
  deltaBetweenRuns: number;
8
8
  firstRun: boolean;
9
- constructor(world: World<C>, options?: SystemConfig);
9
+ constructor(world: BaseWorld<C>, options?: SystemConfig);
10
10
  init(): void | Promise<void>;
11
11
  clear(): void;
12
12
  finishLoading(): void;
package/dist/world.d.ts CHANGED
@@ -1,39 +1,39 @@
1
1
  import { EventEmitter } from 'eventemitter3';
2
2
  import { MemoryHeap } from '@daneren2005/shared-memory-objects';
3
3
  import MemoryComponent from './memory-component';
4
- import Entity from './entity';
4
+ import BaseEntity from './entity';
5
5
  import type System from './systems/system';
6
6
  import type { ComponentMap, ComponentRegistry } from './component-definition';
7
7
  export interface WorldOptions {
8
8
  heapSize?: number;
9
9
  }
10
- export default class World<C extends ComponentMap = ComponentMap> extends EventEmitter {
10
+ export default class BaseWorld<C extends ComponentMap = ComponentMap> extends EventEmitter {
11
11
  heap: MemoryHeap;
12
12
  registry: ComponentRegistry<C>;
13
13
  components: {
14
14
  [K in keyof C]: MemoryComponent;
15
15
  };
16
- entities: Array<Entity<C>>;
16
+ entities: Array<BaseEntity<C>>;
17
17
  entitiesByEid: {
18
- [eid: number]: Entity<C>;
18
+ [eid: number]: BaseEntity<C>;
19
19
  };
20
20
  systems: Array<System<C>>;
21
21
  gameTime: number;
22
22
  destroyed: boolean;
23
23
  constructor(registry: ComponentRegistry<C>, options?: WorldOptions);
24
24
  init(): Promise<void>;
25
- addEntity(entity: Entity<C>, created?: boolean): Entity<C>;
26
- loadEntity(config: any, created?: boolean): Entity<C>;
27
- removeEntity(entity: Entity<C>): void;
28
- getEntityByEid(eid: number): Entity<C> | undefined;
25
+ addEntity(entity: BaseEntity<C>, created?: boolean): BaseEntity<C>;
26
+ loadEntity(config: any, created?: boolean): BaseEntity<C>;
27
+ removeEntity(entity: BaseEntity<C>): void;
28
+ getEntityByEid(eid: number): BaseEntity<C> | undefined;
29
29
  addSystem<T extends System<C>>(system: T): T;
30
30
  addSystemIfNotExists(system: System<C>): void;
31
31
  removeSystem(name: string): void;
32
32
  update(elapsedTime: number): {
33
33
  lastSystemError?: Error | null;
34
34
  };
35
- addEntityToComponentSystem(entity: Entity<C>, component: keyof C): void;
36
- removeEntityFromComponentSystem(entity: Entity<C>, component: keyof C): void;
35
+ addEntityToComponentSystem(entity: BaseEntity<C>, component: keyof C): void;
36
+ removeEntityFromComponentSystem(entity: BaseEntity<C>, component: keyof C): void;
37
37
  private componentAffectsComponentSystem;
38
38
  destroy(): void;
39
39
  }
package/package.json CHANGED
@@ -1,48 +1,56 @@
1
- {
2
- "name": "@daneren2005/shared-memory-ecs",
3
- "description": "A small, reusable Entity/Component/System core backed by shared memory.",
4
- "author": "Scott Jackson",
5
- "version": "0.0.1",
6
- "type": "module",
7
- "main": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "import": {
12
- "types": "./dist/index.d.ts",
13
- "default": "./dist/index.js"
14
- }
15
- }
16
- },
17
- "files": [
18
- "dist"
19
- ],
20
- "scripts": {
21
- "build": "vite build && tsc --emitDeclarationOnly",
22
- "type-check": "tsc --noEmit -p tsconfig.test.json",
23
- "lint": "cross-env NODE_ENV=production oxlint .",
24
- "lint:fix": "cross-env NODE_ENV=production oxlint --fix .",
25
- "test": "vitest run",
26
- "release": "semantic-release",
27
- "prepare": "husky"
28
- },
29
- "dependencies": {
30
- "@daneren2005/shared-memory-objects": "^0.0.21",
31
- "eventemitter3": "^3.1.2"
32
- },
33
- "devDependencies": {
34
- "@semantic-release/changelog": "^6.0.3",
35
- "@semantic-release/git": "^10.0.1",
36
- "@stylistic/eslint-plugin": "^5.10.0",
37
- "@types/node": "^26.1.1",
38
- "cross-env": "^10.1.0",
39
- "husky": "^9.1.7",
40
- "lint-staged": "^17.0.8",
41
- "oxlint": "^1.73.0",
42
- "oxlint-tsgolint": "^0.24.0",
43
- "semantic-release": "^24.2.9",
44
- "typescript": "^7.0.2",
45
- "vite": "^8.1.4",
46
- "vitest": "^4.1.10"
47
- }
48
- }
1
+ {
2
+ "name": "@daneren2005/shared-memory-ecs",
3
+ "description": "A small, reusable Entity/Component/System core backed by shared memory.",
4
+ "author": "Scott Jackson",
5
+ "version": "1.0.0",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/daneren2005/shared-memory-ecs.git"
10
+ },
11
+ "homepage": "https://github.com/daneren2005/shared-memory-ecs#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/daneren2005/shared-memory-ecs/issues"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "import": {
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
22
+ }
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "scripts": {
29
+ "build": "vite build && tsc --emitDeclarationOnly",
30
+ "type-check": "tsc --noEmit -p tsconfig.test.json",
31
+ "lint": "cross-env NODE_ENV=production oxlint .",
32
+ "lint:fix": "cross-env NODE_ENV=production oxlint --fix .",
33
+ "test": "vitest run",
34
+ "release": "semantic-release",
35
+ "prepare": "husky"
36
+ },
37
+ "dependencies": {
38
+ "@daneren2005/shared-memory-objects": "^0.0.21",
39
+ "eventemitter3": "^3.1.2"
40
+ },
41
+ "devDependencies": {
42
+ "@semantic-release/changelog": "^6.0.3",
43
+ "@semantic-release/git": "^10.0.1",
44
+ "@stylistic/eslint-plugin": "^5.10.0",
45
+ "@types/node": "^26.1.1",
46
+ "cross-env": "^10.1.0",
47
+ "husky": "^9.1.7",
48
+ "lint-staged": "^17.0.8",
49
+ "oxlint": "^1.73.0",
50
+ "oxlint-tsgolint": "^0.24.0",
51
+ "semantic-release": "^25.0.6",
52
+ "typescript": "^7.0.2",
53
+ "vite": "^8.1.4",
54
+ "vitest": "^4.1.10"
55
+ }
56
+ }