@daneren2005/shared-memory-ecs 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{create-component-worker-CaB32Dgn.js → create-component-worker-BM942gjg.js} +41 -16
- package/dist/{create-component-worker-CaB32Dgn.js.map → create-component-worker-BM942gjg.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +87 -20
- package/dist/index.js.map +1 -1
- package/dist/systems/component-system.d.ts +2 -0
- package/dist/systems/entity-system.d.ts +1 -0
- package/dist/systems/iterable-system.d.ts +1 -0
- package/dist/systems/system.d.ts +11 -0
- package/dist/systems/workers/component-worker-message.d.ts +6 -0
- package/dist/worker.js +1 -1
- package/dist/world.d.ts +1 -0
- package/package.json +2 -2
|
@@ -191,20 +191,20 @@ function g(t, n, r) {
|
|
|
191
191
|
for (let e of Object.keys(l)) delete l[e];
|
|
192
192
|
u = void 0;
|
|
193
193
|
} else if (y.type === "run") {
|
|
194
|
-
u && Object.assign(y.world, u), y.world.getString = g;
|
|
194
|
+
u && Object.assign(y.world, u), y.world.getString = g, y.world.heap = d;
|
|
195
195
|
let e = {
|
|
196
196
|
allocateEid: () => m ? Atomics.add(m.data, 0, 1) + 1 : 0,
|
|
197
197
|
allocateComponentBlock: (e, t) => p[e].create(t)
|
|
198
198
|
};
|
|
199
199
|
y.world.allocate = e, h && r && (y.world.buildEntityDescriptor = (t) => s(t, h, r, e));
|
|
200
|
-
let i = performance.now(), a = [],
|
|
200
|
+
let i = performance.now(), a = [], f = {}, v = [], b = [];
|
|
201
201
|
c = o(c, y.entities);
|
|
202
|
-
let
|
|
202
|
+
let x = {};
|
|
203
203
|
Object.entries(y.queries).forEach(([e, t]) => {
|
|
204
204
|
let n = o(l[e] ?? [], t);
|
|
205
|
-
l[e] = n,
|
|
205
|
+
l[e] = n, x[e] = n;
|
|
206
206
|
});
|
|
207
|
-
let
|
|
207
|
+
let S = {
|
|
208
208
|
entityComponentChanged(e, t, n, r) {
|
|
209
209
|
a.push({
|
|
210
210
|
entityId: e,
|
|
@@ -224,7 +224,7 @@ function g(t, n, r) {
|
|
|
224
224
|
});
|
|
225
225
|
},
|
|
226
226
|
emitSystemEvent(e, t) {
|
|
227
|
-
(
|
|
227
|
+
(f[e] ?? (f[e] = [])).push(t);
|
|
228
228
|
},
|
|
229
229
|
entityDied(e) {
|
|
230
230
|
a.push({
|
|
@@ -234,22 +234,47 @@ function g(t, n, r) {
|
|
|
234
234
|
});
|
|
235
235
|
},
|
|
236
236
|
createEntity(e) {
|
|
237
|
-
|
|
237
|
+
v.push(e);
|
|
238
|
+
}
|
|
239
|
+
}, C = !1;
|
|
240
|
+
if (n.preRun) try {
|
|
241
|
+
n.preRun(y.world, c, x, S);
|
|
242
|
+
} catch (e) {
|
|
243
|
+
C = !0, b.push({
|
|
244
|
+
error: e,
|
|
245
|
+
phase: "preRun"
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
C || c.forEach((e) => {
|
|
249
|
+
try {
|
|
250
|
+
n(y.world, e.entityId, e.components, x, S);
|
|
251
|
+
} catch (t) {
|
|
252
|
+
b.push({
|
|
253
|
+
error: t,
|
|
254
|
+
phase: "update",
|
|
255
|
+
entityId: e.entityId
|
|
256
|
+
});
|
|
238
257
|
}
|
|
239
|
-
};
|
|
240
|
-
n.preRun && n.preRun(y.world, c, v, b), c.forEach((e) => {
|
|
241
|
-
n(y.world, e.entityId, e.components, v, b);
|
|
242
258
|
}), n.entityRemoved && y.entities.removed.forEach((e) => {
|
|
243
|
-
|
|
259
|
+
try {
|
|
260
|
+
n.entityRemoved(y.world, e, S);
|
|
261
|
+
} catch (t) {
|
|
262
|
+
b.push({
|
|
263
|
+
error: t,
|
|
264
|
+
phase: "entityRemoved",
|
|
265
|
+
entityId: e
|
|
266
|
+
});
|
|
267
|
+
}
|
|
244
268
|
});
|
|
245
|
-
let
|
|
269
|
+
let w = performance.now() - i;
|
|
246
270
|
_(t, {
|
|
247
271
|
type: "run-complete",
|
|
248
272
|
generation: y.generation,
|
|
249
|
-
runTime:
|
|
273
|
+
runTime: w,
|
|
250
274
|
events: a,
|
|
251
|
-
systemEvents:
|
|
252
|
-
created:
|
|
275
|
+
systemEvents: f,
|
|
276
|
+
created: v,
|
|
277
|
+
errors: b
|
|
253
278
|
});
|
|
254
279
|
}
|
|
255
280
|
};
|
|
@@ -260,4 +285,4 @@ function _(e, t) {
|
|
|
260
285
|
//#endregion
|
|
261
286
|
export { u as a, c, a as d, i as f, l as i, s as l, h as n, d as o, m as r, p as s, g as t, o as u };
|
|
262
287
|
|
|
263
|
-
//# sourceMappingURL=create-component-worker-
|
|
288
|
+
//# sourceMappingURL=create-component-worker-BM942gjg.js.map
|
package/dist/{create-component-worker-CaB32Dgn.js.map → create-component-worker-BM942gjg.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-component-worker-CaB32Dgn.js","names":[],"sources":["../src/memory-component.ts","../src/constant-string-cache.ts","../src/systems/workers/apply-query-delta.ts","../src/actions/build-worker-entity.ts","../src/component.ts","../src/entity-component.ts","../src/actions/kill-entity-worker.ts","../src/actions/create-entity-worker.ts","../src/systems/workers/create-component-worker.ts"],"sourcesContent":["import SharedPool from '@daneren2005/shared-memory-objects/shared-pool';\nimport type { SharedPoolMemory } from '@daneren2005/shared-memory-objects/shared-pool';\nimport type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type { TypedArrayConstructor } from '@daneren2005/shared-memory-objects/interfaces/typed-array-constructor';\n\nexport type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;\n\n// Backed by a SharedPool: all bookkeeping lives in the shared heap, so a worker can reconstruct a handle over\n// the same pool (pass the owner's getSharedMemory() as `memory`) and allocate/read blocks off-thread.\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: SharedPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number, memory?: SharedPoolMemory) {\n\t\tthis.heap = heap;\n\t\tthis.pool = memory\n\t\t\t? new SharedPool<T>(heap, memory)\n\t\t\t: new SharedPool<T>(heap, {\n\t\t\t\ttype,\n\t\t\t\tdataLength,\n\t\t\t});\n\t}\n\n\t// Reconstructs a handle over an existing pool (from the owner's getSharedMemory()) — used in a worker, where the\n\t// pool's type/dataLength are already recorded in the heap header, so no definition is needed.\n\tstatic fromSharedMemory<T extends ComponentTypedArray = ComponentTypedArray>(heap: MemoryHeap, memory: SharedPoolMemory): MemoryComponent<T> {\n\t\treturn new MemoryComponent<T>(heap, Uint32Array as unknown as TypedArrayConstructor<T>, 1, memory);\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn this.pool.getSharedMemory();\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 ConstantString from '@daneren2005/shared-memory-objects/constant-string';\nimport { getPointer } from '@daneren2005/shared-memory-objects/utils/pointer';\nimport type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\n\n// Interns immutable strings in the heap and resolves them back from a pointer. Every distinct value is allocated\n// once as a single ConstantString shared by all users (15 \"Space Ship\" entities point at one allocation), and a\n// pointer resolves to its string through a Map hit before ever rebuilding it from memory. Both sides of the\n// worker boundary hold one: the main thread creates + interns; a worker (with a heap reconstructed from the same\n// SharedArrayBuffers) only ever resolves pointers and caches the results.\nexport default class ConstantStringCache {\n\tprivate heap: MemoryHeap;\n\t// value -> the one interned allocation. Only the creating (main) thread populates this; it owns the memory.\n\tprivate byValue = new Map<string, ConstantString>();\n\t// pointer -> value: the fast lookup every thread checks before touching memory.\n\tprivate byPointer = new Map<number, string>();\n\n\tconstructor(heap: MemoryHeap) {\n\t\tthis.heap = heap;\n\t}\n\n\t// Dedupes on value, so repeated types share a single ConstantString. Main-thread only.\n\tgetOrCreate(value: string): ConstantString {\n\t\tlet existing = this.byValue.get(value);\n\t\tif(existing) {\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst string = new ConstantString(this.heap, value);\n\t\tthis.byValue.set(value, string);\n\t\tthis.byPointer.set(string.pointer, value);\n\n\t\treturn string;\n\t}\n\n\t// pointer -> string, checking the cache before rebuilding from memory. A pointer of 0 is the empty string; a\n\t// pointer into a buffer that has not synced to this thread yet returns undefined.\n\tgetString(pointer: number): string | undefined {\n\t\tif(pointer === 0) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet cached = this.byPointer.get(pointer);\n\t\tif(cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst memory = getPointer(pointer);\n\t\tif(this.heap.buffers[memory.bufferPosition] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst value = new ConstantString(this.heap, memory).value;\n\t\tthis.byPointer.set(pointer, value);\n\n\t\treturn value;\n\t}\n\n\t// Frees every allocation this cache owns and empties the lookups. A worker's cache owns nothing (it only ever\n\t// resolved views), so this just drops its pointer lookups.\n\tclear() {\n\t\tthis.byValue.forEach(string => string.free());\n\t\tthis.byValue.clear();\n\t\tthis.byPointer.clear();\n\t}\n}\n","import type { EntityUpdateComponents, QueryDelta, UpdateEntityConfigObject } from '../component-system';\n\n// Applies a run's delta to a query's persistent list: drop the entities that left, upsert those that joined or\n// changed. A steady-state run carries empty arrays and returns the list untouched. Returns the list (removals\n// rebuild it via filter), so callers must store the returned reference back.\nexport function applyQueryDelta<T extends EntityUpdateComponents>(\n\tlist: Array<UpdateEntityConfigObject<T>>,\n\tdelta: QueryDelta<T>,\n): Array<UpdateEntityConfigObject<T>> {\n\tif(delta.removed.length) {\n\t\tconst removedSet = new Set(delta.removed);\n\t\tlist = list.filter(entry => !removedSet.has(entry.entityId));\n\t}\n\n\tif(delta.added.length) {\n\t\t// Index existing members so a re-added entity replaces its entry in place instead of duplicating.\n\t\tconst indexByEid = new Map<number, number>();\n\t\tlist.forEach((entry, index) => indexByEid.set(entry.entityId, index));\n\n\t\tfor(let entity of delta.added) {\n\t\t\tconst existing = indexByEid.get(entity.entityId);\n\t\t\tif(existing !== undefined) {\n\t\t\t\tlist[existing] = entity;\n\t\t\t} else {\n\t\t\t\tindexByEid.set(entity.entityId, list.length);\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn list;\n}\n","import type { WorkerAllocator, WorkerCreateEntityConfig, WorkerCreatedEntity } from '../systems/component-system';\n\n// The slice of a component definition worker-side creation needs. Both the game's ComponentDefinitionMap and the\n// world's RegisteredComponentRegistry satisfy it.\nexport interface WorkerCreatableComponent {\n\tloadProperties: Array<string>\n\tloadInFinishLoading?: boolean\n\ttoBlock(config: Record<string, unknown>): Array<number>\n}\nexport type WorkerCreateRegistry = { [name: string]: WorkerCreatableComponent };\nexport type FactoryConfigs = { [type: string]: Record<string, unknown> };\n\n// Turns a factory-style config ({ type, ...overrides }) into a WorkerCreatedEntity, off-thread: layers the type's\n// factory template under the overrides, mints an id, and allocates + writes each triggered component's block via its\n// toBlock(). The always-present `entity` component is NOT built here - the main thread builds it on adopt (interning\n// the type is main-thread-only), reading `type`/`isStatic` off this descriptor. Shared by the real worker and the\n// main-thread fallback so both behave identically.\nexport function buildWorkerEntity(\n\tconfig: WorkerCreateEntityConfig,\n\tfactoryConfigs: FactoryConfigs,\n\tregistry: WorkerCreateRegistry,\n\tallocator: WorkerAllocator,\n): WorkerCreatedEntity {\n\tconst template = factoryConfigs[config.type] ?? {};\n\tconst merged: Record<string, unknown> = { ...template, ...config };\n\n\tconst eid = allocator.allocateEid();\n\tconst components: { [name: string]: number } = {};\n\tfor(let name of Object.keys(registry)) {\n\t\t// The entity component is always built on the main thread when the descriptor is adopted (interning the type),\n\t\t// never off-thread - skip it here whether or not the registry includes it.\n\t\tif(name === 'entity') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst definition = registry[name];\n\t\t// Deferred components need the whole world (other entities) that a worker doesn't have; skip them.\n\t\tif(definition.loadInFinishLoading) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(definition.loadProperties.some(prop => prop in merged)) {\n\t\t\tcomponents[name] = allocator.allocateComponentBlock(name, definition.toBlock(merged));\n\t\t}\n\t}\n\n\treturn {\n\t\teid,\n\t\ttype: config.type,\n\t\tisStatic: merged.isStatic as boolean | undefined,\n\t\tcomponents,\n\t};\n}\n","import type { ComponentTypedArray } from './memory-component';\nimport type { BaseComponent } from './component-definition';\n\n// Base class for a memory-backed component accessor. Subclass it, declare prototype get/set accessors over\n// `this.block` indexed by the component's exported *_INDEX constants, and return `new YourComponent(block, index)`\n// from `attach`. Because the accessors live on one shared prototype - not fresh closures captured per entity -\n// reads off thousands of entities every frame stay monomorphic and inline, and constructing a component allocates\n// just the instance instead of a closure per accessor. Components that own no extra memory need nothing else; a\n// subclass that does can take more constructor args (the entity, another pool) and store them as fields.\nexport default abstract class Component<T extends ComponentTypedArray = ComponentTypedArray> implements BaseComponent {\n\treadonly index: number;\n\treadonly block: T;\n\n\tconstructor(block: T, index: number) {\n\t\tthis.block = block;\n\t\tthis.index = index;\n\t}\n}\n","import type { ComponentDefinition } from './component-definition';\nimport Component from './component';\nimport type ConstantStringCache from './constant-string-cache';\n\nexport interface EntityComponent {\n\tindex: number\n\ttype: string\n\tdead: boolean\n\tisStatic: boolean\n}\n\nexport interface EntityComponentConfig {\n\ttype: string\n\tisStatic?: boolean\n}\n\nexport interface EntityComponentSerialization {\n\ttype?: string\n\tdead?: boolean\n}\n\nexport const DEAD_INDEX = 0;\nexport const STATIC_INDEX = 1;\nexport const TYPE_INDEX = 2;\n\n// `type` is stored as a pointer to an interned ConstantString, so the accessor needs the world's string cache\n// (passed in, not captured per instance) to resolve it.\nclass EntityComponentImpl extends Component<Uint32Array> implements EntityComponent {\n\tprivate cache: ConstantStringCache;\n\n\tconstructor(block: Uint32Array, index: number, cache: ConstantStringCache) {\n\t\tsuper(block, index);\n\t\tthis.cache = cache;\n\t}\n\n\tget type() {\n\t\treturn this.cache.getString(this.block[TYPE_INDEX]) ?? '';\n\t}\n\tset type(value: string) {\n\t\tthis.block[TYPE_INDEX] = value ? this.cache.getOrCreate(value).pointer : 0;\n\t}\n\tget dead() {\n\t\treturn this.block[DEAD_INDEX] === 1;\n\t}\n\tset dead(value: boolean) {\n\t\tthis.block[DEAD_INDEX] = value ? 1 : 0;\n\t}\n\tget isStatic() {\n\t\treturn this.block[STATIC_INDEX] === 1;\n\t}\n\tset isStatic(value: boolean) {\n\t\tthis.block[STATIC_INDEX] = value ? 1 : 0;\n\t}\n}\n\nexport const entityDefinition: ComponentDefinition<EntityComponent, Uint32Array, EntityComponentConfig, EntityComponentSerialization> = {\n\ttype: Uint32Array,\n\tsize: 3,\n\tloadProperties: ['type', 'isStatic'],\n\t// The only component that reads the entity (never worker-created): it interns its type string through the heap and\n\t// stores the pointer. `entity` is always passed here since loadComponent runs on the main thread.\n\ttoBlock(config, entity) {\n\t\tconst cache = entity!.world.constantStrings;\n\t\tconst typePointer = config.type ? cache.getOrCreate(config.type).pointer : 0;\n\t\treturn [config.dead ? 1 : 0, config.isStatic ? 1 : 0, typePointer];\n\t},\n\tattach(entity, memory, index) {\n\t\treturn new EntityComponentImpl(memory.getBlock(index), index, entity.world.constantStrings);\n\t},\n\tsave(component) {\n\t\tconst config: EntityComponentSerialization = {};\n\t\tif(component.type) {\n\t\t\tconfig.type = component.type;\n\t\t}\n\t\tif(component.dead) {\n\t\t\tconfig.dead = true;\n\t\t}\n\n\t\treturn config;\n\t},\n};\n","import type { ComponentTypedArray } from '../memory-component';\nimport type { ComponentSystemCallbacks, EntityUpdateComponents } from '../systems/component-system';\nimport { DEAD_INDEX } from '../entity-component';\n\n// Worker-side killEntity: flags the entity dead in its block and reports the death back via callbacks. The\n// entity component must be in the system's query for its block to be available here.\nexport default function killEntityWorker(entityId: number, components: EntityUpdateComponents, callbacks: ComponentSystemCallbacks): void {\n\tconst block = (components as { entity?: ComponentTypedArray }).entity;\n\tif(block) {\n\t\tblock[DEAD_INDEX] = 1;\n\t}\n\n\tcallbacks.entityDied(entityId);\n}\n","import type { ComponentSystemCallbacks, ComponentSystemWorld, WorkerCreateEntityConfig } from '../systems/component-system';\n\n// Worker-side entity creation from a factory config. Pass `{ type: 'ship', ...overrides }`: the worker merges the\n// ship template shipped from the factory, mints a unique id, and allocates + writes every triggered component's block\n// directly into the shared pools (off-thread) via each component's toBlock(). It reports the descriptor back; the main\n// thread adopts it on run-complete (world.adoptEntity), building the `entity` component there and wrapping the\n// worker-written blocks, so the entity first exists on the following frame.\n//\n// Requires the system to be registered with `createsEntities: true` and its worker entry to pass the component\n// registry to createComponentWorker (so the worker has each component's toBlock).\nexport default function createEntityWorker(world: ComponentSystemWorld, config: WorkerCreateEntityConfig, callbacks: ComponentSystemCallbacks): void {\n\tif(!world.buildEntityDescriptor) {\n\t\tthrow new Error('createEntityWorker requires the system to be registered with createsEntities: true and the component registry passed to createComponentWorker');\n\t}\n\n\tcallbacks.createEntity(world.buildEntityDescriptor(config));\n}\n","import MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type AllocatedMemory from '@daneren2005/shared-memory-objects/allocated-memory';\nimport type ComponentWorkerMessage from './component-worker-message';\nimport type { EntityEvent, SystemEvents } from './component-worker-message';\nimport ConstantStringCache from '../../constant-string-cache';\nimport MemoryComponent from '../../memory-component';\nimport type { ComponentDefinitionMap, ComponentMap } from '../../component-definition';\nimport type {\n\tComponentSystemCallbacks, ComponentSystemWorld, EntityQueryComponents, EntityUpdateComponents,\n\tEntityUpdateFunction, QueryDelta, UpdateEntityConfigObject, WorkerCreatedEntity,\n} from '../component-system';\nimport { buildWorkerEntity, type FactoryConfigs } from '../../actions/build-worker-entity';\nimport { applyQueryDelta } from './apply-query-delta';\n\n// The slice of the worker global scope createComponentWorker touches. Passing `self` explicitly (rather than\n// using the global) lets runners like @vitest/web-worker, which inject `self` as a module local, drive it.\nexport interface ComponentWorkerScope {\n\tonmessage: ((e: MessageEvent) => void) | null\n\tpostMessage(message: ComponentWorkerMessage): void\n}\n\nexport default function createComponentWorker<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n>(scope: ComponentWorkerScope, updateFunction: EntityUpdateFunction<C, T, W, D>, definitions?: ComponentDefinitionMap) {\n\t// Persistent lists, carried across runs and mutated by each run's delta (see applyQueryDelta).\n\tlet entities: Array<UpdateEntityConfigObject<T>> = [];\n\tconst queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\t// What updateFunction.init returned: persistent state (e.g. a seeded RNG) merged onto `world` each run.\n\tlet worldExtension: Partial<W> | undefined;\n\tlet heap: MemoryHeap | undefined;\n\tlet stringCache: ConstantStringCache | undefined;\n\t// Reconstructed pool handles over the world's shared state, plus the factory templates - for off-thread entity\n\t// allocation. `definitions` (passed by the game's worker entry) supplies each component's toBlock/loadProperties.\n\tlet pools: { [name: string]: MemoryComponent } = {};\n\tlet eidCounter: AllocatedMemory | undefined;\n\tlet factoryConfigs: FactoryConfigs | undefined;\n\tconst getString = (pointer: number): string => stringCache?.getString(pointer) ?? '';\n\n\tscope.onmessage = function(e) {\n\t\tconst message = e.data as ComponentWorkerMessage<W, D>;\n\n\t\tif(message.type === 'init') {\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'init-complete',\n\t\t\t});\n\t\t} else if(message.type === 'load') {\n\t\t\tif(message.heap) {\n\t\t\t\theap = new MemoryHeap(message.heap);\n\t\t\t\tstringCache = new ConstantStringCache(heap);\n\t\t\t\t// Report any buffer this worker grows (while allocating off-thread) back to the main thread, which adopts\n\t\t\t\t// it and fans it out to sibling workers.\n\t\t\t\theap.addOnGrowBufferHandlers(buffer => postMessageTyped(scope, { type: 'grow-buffer-from-worker', buffer }));\n\t\t\t}\n\t\t\tif(heap && message.sharedMemory) {\n\t\t\t\tpools = {};\n\t\t\t\tfor(const name of Object.keys(message.sharedMemory.components)) {\n\t\t\t\t\tpools[name] = MemoryComponent.fromSharedMemory(heap, message.sharedMemory.components[name]);\n\t\t\t\t}\n\t\t\t\teidCounter = heap.getSharedAlloc(message.sharedMemory.eidCounter);\n\t\t\t}\n\t\t\tfactoryConfigs = message.factoryConfigs;\n\t\t\tworldExtension = updateFunction.init?.(message.data) ?? undefined;\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'grow-buffer') {\n\t\t\t// Never replace a buffer this worker already holds: the main thread fans a worker-grown buffer back out to\n\t\t\t// every worker (including the one that grew it), and overwriting our own live MemoryBuffer would discard its\n\t\t\t// allocation bookkeeping. The SharedArrayBuffer at that position is already the same one.\n\t\t\tif(heap && heap.buffers[message.buffer.bufferPosition] === undefined) {\n\t\t\t\theap.addSharedBuffer(message.buffer);\n\t\t\t}\n\t\t} else if(message.type === 'reset') {\n\t\t\t// Drop the persistent lists so a reused world starts empty; worldExtension is refreshed by the next load.\n\t\t\tentities = [];\n\t\t\tfor(const key of Object.keys(queryEntities)) {\n\t\t\t\tdelete queryEntities[key];\n\t\t\t}\n\t\t\tworldExtension = undefined;\n\t\t} else if(message.type === 'run') {\n\t\t\tif(worldExtension) {\n\t\t\t\tObject.assign(message.world, worldExtension);\n\t\t\t}\n\t\t\tmessage.world.getString = getString;\n\t\t\tconst allocator = {\n\t\t\t\tallocateEid: () => eidCounter ? Atomics.add(eidCounter.data, 0, 1) + 1 : 0,\n\t\t\t\tallocateComponentBlock: (name: string, values: Array<number>) => pools[name].create(values),\n\t\t\t};\n\t\t\tmessage.world.allocate = allocator;\n\t\t\t// Only a system registered with createsEntities (factoryConfigs shipped) whose worker entry passed the\n\t\t\t// component definitions can create entities from a config.\n\t\t\tif(factoryConfigs && definitions) {\n\t\t\t\tmessage.world.buildEntityDescriptor = config => buildWorkerEntity(config, factoryConfigs!, definitions, allocator);\n\t\t\t}\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<EntityEvent> = [];\n\t\t\tlet systemEvents: SystemEvents = {};\n\t\t\tlet createdEntities: Array<WorkerCreatedEntity> = [];\n\n\t\t\tentities = applyQueryDelta(entities, message.entities as QueryDelta<T>);\n\n\t\t\tlet queries: EntityQueryComponents<C> = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, delta]) => {\n\t\t\t\tconst list = applyQueryDelta(queryEntities[queryKey] ?? [], delta as QueryDelta<T>);\n\t\t\t\tqueryEntities[queryKey] = list;\n\t\t\t\tqueries[queryKey] = list;\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\temitEntityEvent(entityId: number, event: string, ...args: Array<unknown>) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\targs,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\temitSystemEvent(event: string, entityId: number) {\n\t\t\t\t\t(systemEvents[event] ?? (systemEvents[event] = [])).push(entityId);\n\t\t\t\t},\n\t\t\t\tentityDied(entityId: number) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'death',\n\t\t\t\t\t\targs: [],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tcreateEntity(entity: WorkerCreatedEntity) {\n\t\t\t\t\tcreatedEntities.push(entity);\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\tif(updateFunction.entityRemoved) {\n\t\t\t\tmessage.entities.removed.forEach(entityId => {\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(scope, {\n\t\t\t\ttype: 'run-complete',\n\t\t\t\tgeneration: message.generation,\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tsystemEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction postMessageTyped(scope: ComponentWorkerScope, message: ComponentWorkerMessage) {\n\tscope.postMessage(message);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create-component-worker-BM942gjg.js","names":[],"sources":["../src/memory-component.ts","../src/constant-string-cache.ts","../src/systems/workers/apply-query-delta.ts","../src/actions/build-worker-entity.ts","../src/component.ts","../src/entity-component.ts","../src/actions/kill-entity-worker.ts","../src/actions/create-entity-worker.ts","../src/systems/workers/create-component-worker.ts"],"sourcesContent":["import SharedPool from '@daneren2005/shared-memory-objects/shared-pool';\nimport type { SharedPoolMemory } from '@daneren2005/shared-memory-objects/shared-pool';\nimport type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type { TypedArrayConstructor } from '@daneren2005/shared-memory-objects/interfaces/typed-array-constructor';\n\nexport type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;\n\n// Backed by a SharedPool: all bookkeeping lives in the shared heap, so a worker can reconstruct a handle over\n// the same pool (pass the owner's getSharedMemory() as `memory`) and allocate/read blocks off-thread.\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: SharedPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number, memory?: SharedPoolMemory) {\n\t\tthis.heap = heap;\n\t\tthis.pool = memory\n\t\t\t? new SharedPool<T>(heap, memory)\n\t\t\t: new SharedPool<T>(heap, {\n\t\t\t\ttype,\n\t\t\t\tdataLength,\n\t\t\t});\n\t}\n\n\t// Reconstructs a handle over an existing pool (from the owner's getSharedMemory()) — used in a worker, where the\n\t// pool's type/dataLength are already recorded in the heap header, so no definition is needed.\n\tstatic fromSharedMemory<T extends ComponentTypedArray = ComponentTypedArray>(heap: MemoryHeap, memory: SharedPoolMemory): MemoryComponent<T> {\n\t\treturn new MemoryComponent<T>(heap, Uint32Array as unknown as TypedArrayConstructor<T>, 1, memory);\n\t}\n\n\tgetSharedMemory(): SharedPoolMemory {\n\t\treturn this.pool.getSharedMemory();\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 ConstantString from '@daneren2005/shared-memory-objects/constant-string';\nimport { getPointer } from '@daneren2005/shared-memory-objects/utils/pointer';\nimport type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\n\n// Interns immutable strings in the heap and resolves them back from a pointer. Every distinct value is allocated\n// once as a single ConstantString shared by all users (15 \"Space Ship\" entities point at one allocation), and a\n// pointer resolves to its string through a Map hit before ever rebuilding it from memory. Both sides of the\n// worker boundary hold one: the main thread creates + interns; a worker (with a heap reconstructed from the same\n// SharedArrayBuffers) only ever resolves pointers and caches the results.\nexport default class ConstantStringCache {\n\tprivate heap: MemoryHeap;\n\t// value -> the one interned allocation. Only the creating (main) thread populates this; it owns the memory.\n\tprivate byValue = new Map<string, ConstantString>();\n\t// pointer -> value: the fast lookup every thread checks before touching memory.\n\tprivate byPointer = new Map<number, string>();\n\n\tconstructor(heap: MemoryHeap) {\n\t\tthis.heap = heap;\n\t}\n\n\t// Dedupes on value, so repeated types share a single ConstantString. Main-thread only.\n\tgetOrCreate(value: string): ConstantString {\n\t\tlet existing = this.byValue.get(value);\n\t\tif(existing) {\n\t\t\treturn existing;\n\t\t}\n\n\t\tconst string = new ConstantString(this.heap, value);\n\t\tthis.byValue.set(value, string);\n\t\tthis.byPointer.set(string.pointer, value);\n\n\t\treturn string;\n\t}\n\n\t// pointer -> string, checking the cache before rebuilding from memory. A pointer of 0 is the empty string; a\n\t// pointer into a buffer that has not synced to this thread yet returns undefined.\n\tgetString(pointer: number): string | undefined {\n\t\tif(pointer === 0) {\n\t\t\treturn '';\n\t\t}\n\n\t\tlet cached = this.byPointer.get(pointer);\n\t\tif(cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst memory = getPointer(pointer);\n\t\tif(this.heap.buffers[memory.bufferPosition] === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst value = new ConstantString(this.heap, memory).value;\n\t\tthis.byPointer.set(pointer, value);\n\n\t\treturn value;\n\t}\n\n\t// Frees every allocation this cache owns and empties the lookups. A worker's cache owns nothing (it only ever\n\t// resolved views), so this just drops its pointer lookups.\n\tclear() {\n\t\tthis.byValue.forEach(string => string.free());\n\t\tthis.byValue.clear();\n\t\tthis.byPointer.clear();\n\t}\n}\n","import type { EntityUpdateComponents, QueryDelta, UpdateEntityConfigObject } from '../component-system';\n\n// Applies a run's delta to a query's persistent list: drop the entities that left, upsert those that joined or\n// changed. A steady-state run carries empty arrays and returns the list untouched. Returns the list (removals\n// rebuild it via filter), so callers must store the returned reference back.\nexport function applyQueryDelta<T extends EntityUpdateComponents>(\n\tlist: Array<UpdateEntityConfigObject<T>>,\n\tdelta: QueryDelta<T>,\n): Array<UpdateEntityConfigObject<T>> {\n\tif(delta.removed.length) {\n\t\tconst removedSet = new Set(delta.removed);\n\t\tlist = list.filter(entry => !removedSet.has(entry.entityId));\n\t}\n\n\tif(delta.added.length) {\n\t\t// Index existing members so a re-added entity replaces its entry in place instead of duplicating.\n\t\tconst indexByEid = new Map<number, number>();\n\t\tlist.forEach((entry, index) => indexByEid.set(entry.entityId, index));\n\n\t\tfor(let entity of delta.added) {\n\t\t\tconst existing = indexByEid.get(entity.entityId);\n\t\t\tif(existing !== undefined) {\n\t\t\t\tlist[existing] = entity;\n\t\t\t} else {\n\t\t\t\tindexByEid.set(entity.entityId, list.length);\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn list;\n}\n","import type { WorkerAllocator, WorkerCreateEntityConfig, WorkerCreatedEntity } from '../systems/component-system';\n\n// The slice of a component definition worker-side creation needs. Both the game's ComponentDefinitionMap and the\n// world's RegisteredComponentRegistry satisfy it.\nexport interface WorkerCreatableComponent {\n\tloadProperties: Array<string>\n\tloadInFinishLoading?: boolean\n\ttoBlock(config: Record<string, unknown>): Array<number>\n}\nexport type WorkerCreateRegistry = { [name: string]: WorkerCreatableComponent };\nexport type FactoryConfigs = { [type: string]: Record<string, unknown> };\n\n// Turns a factory-style config ({ type, ...overrides }) into a WorkerCreatedEntity, off-thread: layers the type's\n// factory template under the overrides, mints an id, and allocates + writes each triggered component's block via its\n// toBlock(). The always-present `entity` component is NOT built here - the main thread builds it on adopt (interning\n// the type is main-thread-only), reading `type`/`isStatic` off this descriptor. Shared by the real worker and the\n// main-thread fallback so both behave identically.\nexport function buildWorkerEntity(\n\tconfig: WorkerCreateEntityConfig,\n\tfactoryConfigs: FactoryConfigs,\n\tregistry: WorkerCreateRegistry,\n\tallocator: WorkerAllocator,\n): WorkerCreatedEntity {\n\tconst template = factoryConfigs[config.type] ?? {};\n\tconst merged: Record<string, unknown> = { ...template, ...config };\n\n\tconst eid = allocator.allocateEid();\n\tconst components: { [name: string]: number } = {};\n\tfor(let name of Object.keys(registry)) {\n\t\t// The entity component is always built on the main thread when the descriptor is adopted (interning the type),\n\t\t// never off-thread - skip it here whether or not the registry includes it.\n\t\tif(name === 'entity') {\n\t\t\tcontinue;\n\t\t}\n\t\tconst definition = registry[name];\n\t\t// Deferred components need the whole world (other entities) that a worker doesn't have; skip them.\n\t\tif(definition.loadInFinishLoading) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(definition.loadProperties.some(prop => prop in merged)) {\n\t\t\tcomponents[name] = allocator.allocateComponentBlock(name, definition.toBlock(merged));\n\t\t}\n\t}\n\n\treturn {\n\t\teid,\n\t\ttype: config.type,\n\t\tisStatic: merged.isStatic as boolean | undefined,\n\t\tcomponents,\n\t};\n}\n","import type { ComponentTypedArray } from './memory-component';\nimport type { BaseComponent } from './component-definition';\n\n// Base class for a memory-backed component accessor. Subclass it, declare prototype get/set accessors over\n// `this.block` indexed by the component's exported *_INDEX constants, and return `new YourComponent(block, index)`\n// from `attach`. Because the accessors live on one shared prototype - not fresh closures captured per entity -\n// reads off thousands of entities every frame stay monomorphic and inline, and constructing a component allocates\n// just the instance instead of a closure per accessor. Components that own no extra memory need nothing else; a\n// subclass that does can take more constructor args (the entity, another pool) and store them as fields.\nexport default abstract class Component<T extends ComponentTypedArray = ComponentTypedArray> implements BaseComponent {\n\treadonly index: number;\n\treadonly block: T;\n\n\tconstructor(block: T, index: number) {\n\t\tthis.block = block;\n\t\tthis.index = index;\n\t}\n}\n","import type { ComponentDefinition } from './component-definition';\nimport Component from './component';\nimport type ConstantStringCache from './constant-string-cache';\n\nexport interface EntityComponent {\n\tindex: number\n\ttype: string\n\tdead: boolean\n\tisStatic: boolean\n}\n\nexport interface EntityComponentConfig {\n\ttype: string\n\tisStatic?: boolean\n}\n\nexport interface EntityComponentSerialization {\n\ttype?: string\n\tdead?: boolean\n}\n\nexport const DEAD_INDEX = 0;\nexport const STATIC_INDEX = 1;\nexport const TYPE_INDEX = 2;\n\n// `type` is stored as a pointer to an interned ConstantString, so the accessor needs the world's string cache\n// (passed in, not captured per instance) to resolve it.\nclass EntityComponentImpl extends Component<Uint32Array> implements EntityComponent {\n\tprivate cache: ConstantStringCache;\n\n\tconstructor(block: Uint32Array, index: number, cache: ConstantStringCache) {\n\t\tsuper(block, index);\n\t\tthis.cache = cache;\n\t}\n\n\tget type() {\n\t\treturn this.cache.getString(this.block[TYPE_INDEX]) ?? '';\n\t}\n\tset type(value: string) {\n\t\tthis.block[TYPE_INDEX] = value ? this.cache.getOrCreate(value).pointer : 0;\n\t}\n\tget dead() {\n\t\treturn this.block[DEAD_INDEX] === 1;\n\t}\n\tset dead(value: boolean) {\n\t\tthis.block[DEAD_INDEX] = value ? 1 : 0;\n\t}\n\tget isStatic() {\n\t\treturn this.block[STATIC_INDEX] === 1;\n\t}\n\tset isStatic(value: boolean) {\n\t\tthis.block[STATIC_INDEX] = value ? 1 : 0;\n\t}\n}\n\nexport const entityDefinition: ComponentDefinition<EntityComponent, Uint32Array, EntityComponentConfig, EntityComponentSerialization> = {\n\ttype: Uint32Array,\n\tsize: 3,\n\tloadProperties: ['type', 'isStatic'],\n\t// The only component that reads the entity (never worker-created): it interns its type string through the heap and\n\t// stores the pointer. `entity` is always passed here since loadComponent runs on the main thread.\n\ttoBlock(config, entity) {\n\t\tconst cache = entity!.world.constantStrings;\n\t\tconst typePointer = config.type ? cache.getOrCreate(config.type).pointer : 0;\n\t\treturn [config.dead ? 1 : 0, config.isStatic ? 1 : 0, typePointer];\n\t},\n\tattach(entity, memory, index) {\n\t\treturn new EntityComponentImpl(memory.getBlock(index), index, entity.world.constantStrings);\n\t},\n\tsave(component) {\n\t\tconst config: EntityComponentSerialization = {};\n\t\tif(component.type) {\n\t\t\tconfig.type = component.type;\n\t\t}\n\t\tif(component.dead) {\n\t\t\tconfig.dead = true;\n\t\t}\n\n\t\treturn config;\n\t},\n};\n","import type { ComponentTypedArray } from '../memory-component';\nimport type { ComponentSystemCallbacks, EntityUpdateComponents } from '../systems/component-system';\nimport { DEAD_INDEX } from '../entity-component';\n\n// Worker-side killEntity: flags the entity dead in its block and reports the death back via callbacks. The\n// entity component must be in the system's query for its block to be available here.\nexport default function killEntityWorker(entityId: number, components: EntityUpdateComponents, callbacks: ComponentSystemCallbacks): void {\n\tconst block = (components as { entity?: ComponentTypedArray }).entity;\n\tif(block) {\n\t\tblock[DEAD_INDEX] = 1;\n\t}\n\n\tcallbacks.entityDied(entityId);\n}\n","import type { ComponentSystemCallbacks, ComponentSystemWorld, WorkerCreateEntityConfig } from '../systems/component-system';\n\n// Worker-side entity creation from a factory config. Pass `{ type: 'ship', ...overrides }`: the worker merges the\n// ship template shipped from the factory, mints a unique id, and allocates + writes every triggered component's block\n// directly into the shared pools (off-thread) via each component's toBlock(). It reports the descriptor back; the main\n// thread adopts it on run-complete (world.adoptEntity), building the `entity` component there and wrapping the\n// worker-written blocks, so the entity first exists on the following frame.\n//\n// Requires the system to be registered with `createsEntities: true` and its worker entry to pass the component\n// registry to createComponentWorker (so the worker has each component's toBlock).\nexport default function createEntityWorker(world: ComponentSystemWorld, config: WorkerCreateEntityConfig, callbacks: ComponentSystemCallbacks): void {\n\tif(!world.buildEntityDescriptor) {\n\t\tthrow new Error('createEntityWorker requires the system to be registered with createsEntities: true and the component registry passed to createComponentWorker');\n\t}\n\n\tcallbacks.createEntity(world.buildEntityDescriptor(config));\n}\n","import MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type AllocatedMemory from '@daneren2005/shared-memory-objects/allocated-memory';\nimport type ComponentWorkerMessage from './component-worker-message';\nimport type { EntityEvent, SystemEvents, WorkerRunError } from './component-worker-message';\nimport ConstantStringCache from '../../constant-string-cache';\nimport MemoryComponent from '../../memory-component';\nimport type { ComponentDefinitionMap, ComponentMap } from '../../component-definition';\nimport type {\n\tComponentSystemCallbacks, ComponentSystemWorld, EntityQueryComponents, EntityUpdateComponents,\n\tEntityUpdateFunction, QueryDelta, UpdateEntityConfigObject, WorkerCreatedEntity,\n} from '../component-system';\nimport { buildWorkerEntity, type FactoryConfigs } from '../../actions/build-worker-entity';\nimport { applyQueryDelta } from './apply-query-delta';\n\n// The slice of the worker global scope createComponentWorker touches. Passing `self` explicitly (rather than\n// using the global) lets runners like @vitest/web-worker, which inject `self` as a module local, drive it.\nexport interface ComponentWorkerScope {\n\tonmessage: ((e: MessageEvent) => void) | null\n\tpostMessage(message: ComponentWorkerMessage): void\n}\n\nexport default function createComponentWorker<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n>(scope: ComponentWorkerScope, updateFunction: EntityUpdateFunction<C, T, W, D>, definitions?: ComponentDefinitionMap) {\n\t// Persistent lists, carried across runs and mutated by each run's delta (see applyQueryDelta).\n\tlet entities: Array<UpdateEntityConfigObject<T>> = [];\n\tconst queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\t// What updateFunction.init returned: persistent state (e.g. a seeded RNG) merged onto `world` each run.\n\tlet worldExtension: Partial<W> | undefined;\n\tlet heap: MemoryHeap | undefined;\n\tlet stringCache: ConstantStringCache | undefined;\n\t// Reconstructed pool handles over the world's shared state, plus the factory templates - for off-thread entity\n\t// allocation. `definitions` (passed by the game's worker entry) supplies each component's toBlock/loadProperties.\n\tlet pools: { [name: string]: MemoryComponent } = {};\n\tlet eidCounter: AllocatedMemory | undefined;\n\tlet factoryConfigs: FactoryConfigs | undefined;\n\tconst getString = (pointer: number): string => stringCache?.getString(pointer) ?? '';\n\n\tscope.onmessage = function(e) {\n\t\tconst message = e.data as ComponentWorkerMessage<W, D>;\n\n\t\tif(message.type === 'init') {\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'init-complete',\n\t\t\t});\n\t\t} else if(message.type === 'load') {\n\t\t\tif(message.heap) {\n\t\t\t\theap = new MemoryHeap(message.heap);\n\t\t\t\tstringCache = new ConstantStringCache(heap);\n\t\t\t\t// Report any buffer this worker grows (while allocating off-thread) back to the main thread, which adopts\n\t\t\t\t// it and fans it out to sibling workers.\n\t\t\t\theap.addOnGrowBufferHandlers(buffer => postMessageTyped(scope, { type: 'grow-buffer-from-worker', buffer }));\n\t\t\t}\n\t\t\tif(heap && message.sharedMemory) {\n\t\t\t\tpools = {};\n\t\t\t\tfor(const name of Object.keys(message.sharedMemory.components)) {\n\t\t\t\t\tpools[name] = MemoryComponent.fromSharedMemory(heap, message.sharedMemory.components[name]);\n\t\t\t\t}\n\t\t\t\teidCounter = heap.getSharedAlloc(message.sharedMemory.eidCounter);\n\t\t\t}\n\t\t\tfactoryConfigs = message.factoryConfigs;\n\t\t\tworldExtension = updateFunction.init?.(message.data) ?? undefined;\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'grow-buffer') {\n\t\t\t// Never replace a buffer this worker already holds: the main thread fans a worker-grown buffer back out to\n\t\t\t// every worker (including the one that grew it), and overwriting our own live MemoryBuffer would discard its\n\t\t\t// allocation bookkeeping. The SharedArrayBuffer at that position is already the same one.\n\t\t\tif(heap && heap.buffers[message.buffer.bufferPosition] === undefined) {\n\t\t\t\theap.addSharedBuffer(message.buffer);\n\t\t\t}\n\t\t} else if(message.type === 'reset') {\n\t\t\t// Drop the persistent lists so a reused world starts empty; worldExtension is refreshed by the next load.\n\t\t\tentities = [];\n\t\t\tfor(const key of Object.keys(queryEntities)) {\n\t\t\t\tdelete queryEntities[key];\n\t\t\t}\n\t\t\tworldExtension = undefined;\n\t\t} else if(message.type === 'run') {\n\t\t\tif(worldExtension) {\n\t\t\t\tObject.assign(message.world, worldExtension);\n\t\t\t}\n\t\t\tmessage.world.getString = getString;\n\t\t\tmessage.world.heap = heap;\n\t\t\tconst allocator = {\n\t\t\t\tallocateEid: () => eidCounter ? Atomics.add(eidCounter.data, 0, 1) + 1 : 0,\n\t\t\t\tallocateComponentBlock: (name: string, values: Array<number>) => pools[name].create(values),\n\t\t\t};\n\t\t\tmessage.world.allocate = allocator;\n\t\t\t// Only a system registered with createsEntities (factoryConfigs shipped) whose worker entry passed the\n\t\t\t// component definitions can create entities from a config.\n\t\t\tif(factoryConfigs && definitions) {\n\t\t\t\tmessage.world.buildEntityDescriptor = config => buildWorkerEntity(config, factoryConfigs!, definitions, allocator);\n\t\t\t}\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<EntityEvent> = [];\n\t\t\tlet systemEvents: SystemEvents = {};\n\t\t\tlet createdEntities: Array<WorkerCreatedEntity> = [];\n\t\t\tlet errors: Array<WorkerRunError> = [];\n\n\t\t\tentities = applyQueryDelta(entities, message.entities as QueryDelta<T>);\n\n\t\t\tlet queries: EntityQueryComponents<C> = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, delta]) => {\n\t\t\t\tconst list = applyQueryDelta(queryEntities[queryKey] ?? [], delta as QueryDelta<T>);\n\t\t\t\tqueryEntities[queryKey] = list;\n\t\t\t\tqueries[queryKey] = list;\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\temitEntityEvent(entityId: number, event: string, ...args: Array<unknown>) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\targs,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\temitSystemEvent(event: string, entityId: number) {\n\t\t\t\t\t(systemEvents[event] ?? (systemEvents[event] = [])).push(entityId);\n\t\t\t\t},\n\t\t\t\tentityDied(entityId: number) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'death',\n\t\t\t\t\t\targs: [],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tcreateEntity(entity: WorkerCreatedEntity) {\n\t\t\t\t\tcreatedEntities.push(entity);\n\t\t\t\t},\n\t\t\t};\n\t\t\tlet preRunFailed = false;\n\t\t\tif(updateFunction.preRun) {\n\t\t\t\ttry {\n\t\t\t\t\tupdateFunction.preRun(message.world, entities, queries, callbacks);\n\t\t\t\t} catch(err) {\n\t\t\t\t\tpreRunFailed = true;\n\t\t\t\t\terrors.push({ error: err as Error, phase: 'preRun' });\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// preRun sets up the run's state; if it threw, skip the entity loop rather than run over half-prepared data.\n\t\t\tif(!preRunFailed) {\n\t\t\t\tentities.forEach(entity => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tupdateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\t// One entity failing must not stop the rest of the run.\n\t\t\t\t\t\terrors.push({ error: err as Error, phase: 'update', entityId: entity.entityId });\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif(updateFunction.entityRemoved) {\n\t\t\t\tmessage.entities.removed.forEach(entityId => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tupdateFunction.entityRemoved!(message.world, entityId, callbacks);\n\t\t\t\t\t} catch(err) {\n\t\t\t\t\t\terrors.push({ error: err as Error, phase: 'entityRemoved', entityId });\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst runTime = performance.now() - start;\n\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'run-complete',\n\t\t\t\tgeneration: message.generation,\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tsystemEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t\terrors,\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction postMessageTyped(scope: ComponentWorkerScope, message: ComponentWorkerMessage) {\n\tscope.postMessage(message);\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export type { ComponentTypedArray } from './memory-component';
|
|
|
15
15
|
export { default as Component } from './component';
|
|
16
16
|
export type { BaseComponent, ComponentMap, ComponentDefinition, ComponentDefinitionMap, ComponentRegistry, ComponentsOf, EntityConfigOf, RegisteredComponentDefinition, RegisteredComponentRegistry, } from './component-definition';
|
|
17
17
|
export { default as System } from './systems/system';
|
|
18
|
-
export type { SystemConfig } from './systems/system';
|
|
18
|
+
export type { SystemConfig, SystemError, SystemErrorPhase } from './systems/system';
|
|
19
19
|
export { default as IterableSystem } from './systems/iterable-system';
|
|
20
20
|
export type { IterableSystemConfig } from './systems/iterable-system';
|
|
21
21
|
export { default as EntitySystem } from './systems/entity-system';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./create-component-worker-
|
|
1
|
+
import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u, u as d } from "./create-component-worker-BM942gjg.js";
|
|
2
2
|
import f from "@daneren2005/shared-memory-objects/memory-heap";
|
|
3
3
|
import { MAX_BYTE_OFFSET_LENGTH as p } from "@daneren2005/shared-memory-objects/utils/pointer";
|
|
4
4
|
//#region \0rolldown/runtime.js
|
|
@@ -187,6 +187,17 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
187
187
|
return this.deltaBetweenRuns > 0 && (e = this.currentDelta % this.deltaBetweenRuns), this.run(this.currentDelta - e), this.currentDelta = e, this.firstRun = !1, this.onRunFinished(), !0;
|
|
188
188
|
} else return !1;
|
|
189
189
|
}
|
|
190
|
+
onError(e, t = {}) {
|
|
191
|
+
let n = t.entityId === void 0 ? "" : ` (entity ${t.entityId})`;
|
|
192
|
+
console.error(`Error in system ${this.name}${n}: ${e.message}`, e);
|
|
193
|
+
let r = {
|
|
194
|
+
system: this.name,
|
|
195
|
+
error: e,
|
|
196
|
+
entityId: t.entityId,
|
|
197
|
+
phase: t.phase
|
|
198
|
+
};
|
|
199
|
+
this.world.emit("system-error", r);
|
|
200
|
+
}
|
|
190
201
|
onRunFinished() {
|
|
191
202
|
this.world.notifySystemRunCompleted(this);
|
|
192
203
|
}
|
|
@@ -226,14 +237,30 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
226
237
|
}
|
|
227
238
|
runIterables(e, t) {
|
|
228
239
|
let n = performance.now();
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
240
|
+
try {
|
|
241
|
+
this.beforeRunIterables();
|
|
242
|
+
} catch (e) {
|
|
243
|
+
this.onError(e, { phase: "preRun" }), this.remainingInstancesToRun = [], this.remainingInstancesStartTime = null;
|
|
232
244
|
return;
|
|
233
245
|
}
|
|
246
|
+
for (let r = 0; r < e.length; r++) {
|
|
247
|
+
try {
|
|
248
|
+
this.updateIterable(e[r], t);
|
|
249
|
+
} catch (t) {
|
|
250
|
+
this.onError(t, {
|
|
251
|
+
phase: "update",
|
|
252
|
+
entityId: this.getIterableEntityId(e[r])
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
if (r % this.iterationsPerCheck === 0 && performance.now() - n >= this.maxMsPerFrame) {
|
|
256
|
+
this.remainingInstancesToRun = e.slice(r + 1), this.remainingInstancesStartTime = t;
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
234
260
|
this.remainingInstancesToRun = [], this.remainingInstancesStartTime = null;
|
|
235
261
|
}
|
|
236
262
|
beforeRunIterables() {}
|
|
263
|
+
getIterableEntityId(e) {}
|
|
237
264
|
}, E = class extends T {
|
|
238
265
|
entities = /* @__PURE__ */ new Map();
|
|
239
266
|
options;
|
|
@@ -258,6 +285,9 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
258
285
|
filterEntity(e) {
|
|
259
286
|
return !e.components.entity.isStatic;
|
|
260
287
|
}
|
|
288
|
+
getIterableEntityId(e) {
|
|
289
|
+
return e.eid;
|
|
290
|
+
}
|
|
261
291
|
isEntityInSystem(e) {
|
|
262
292
|
return this.entities.has(e.eid);
|
|
263
293
|
}
|
|
@@ -293,18 +323,18 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
293
323
|
else if (e.type === "load") this.worldExtension = this.updateFunction.init?.(e.data) ?? void 0, this.onMessageTyped({ type: "loaded" });
|
|
294
324
|
else if (e.type === "reset") this.entities = [], this.queryEntities = {};
|
|
295
325
|
else if (e.type === "run") {
|
|
296
|
-
if (this.worldExtension && Object.assign(e.world, this.worldExtension), e.world.getString = (e) => this.world.constantStrings.getString(e) ?? "", e.world.allocate = this.allocator, this.createsEntities) {
|
|
326
|
+
if (this.worldExtension && Object.assign(e.world, this.worldExtension), e.world.getString = (e) => this.world.constantStrings.getString(e) ?? "", e.world.heap = this.world.heap, e.world.allocate = this.allocator, this.createsEntities) {
|
|
297
327
|
let t = this.world.registry;
|
|
298
328
|
e.world.buildEntityDescriptor = (e) => a(e, this.world.factory.configs, t, this.allocator);
|
|
299
329
|
}
|
|
300
|
-
let t = performance.now(), n = [], r = {}, i = [];
|
|
330
|
+
let t = performance.now(), n = [], r = {}, i = [], o = [];
|
|
301
331
|
this.entities = d(this.entities, e.entities);
|
|
302
|
-
let
|
|
332
|
+
let s = {};
|
|
303
333
|
Object.entries(e.queries).forEach(([e, t]) => {
|
|
304
334
|
let n = d(this.queryEntities[e] ?? [], t);
|
|
305
|
-
this.queryEntities[e] = n,
|
|
335
|
+
this.queryEntities[e] = n, s[e] = n;
|
|
306
336
|
});
|
|
307
|
-
let
|
|
337
|
+
let c = {
|
|
308
338
|
entityComponentChanged(e, t, r, i) {
|
|
309
339
|
n.push({
|
|
310
340
|
entityId: e,
|
|
@@ -336,18 +366,43 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
336
366
|
createEntity(e) {
|
|
337
367
|
i.push(e);
|
|
338
368
|
}
|
|
339
|
-
};
|
|
340
|
-
if (this.updateFunction.preRun
|
|
341
|
-
this.updateFunction(e.world,
|
|
342
|
-
}
|
|
343
|
-
|
|
369
|
+
}, l = !1;
|
|
370
|
+
if (this.updateFunction.preRun) try {
|
|
371
|
+
this.updateFunction.preRun(e.world, this.entities, s, c);
|
|
372
|
+
} catch (e) {
|
|
373
|
+
l = !0, o.push({
|
|
374
|
+
error: e,
|
|
375
|
+
phase: "preRun"
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
if (l || this.entities.forEach((t) => {
|
|
379
|
+
try {
|
|
380
|
+
this.updateFunction(e.world, t.entityId, t.components, s, c);
|
|
381
|
+
} catch (e) {
|
|
382
|
+
o.push({
|
|
383
|
+
error: e,
|
|
384
|
+
phase: "update",
|
|
385
|
+
entityId: t.entityId
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}), this.updateFunction.entityRemoved) for (let t of e.entities.removed) try {
|
|
389
|
+
this.updateFunction.entityRemoved(e.world, t, c);
|
|
390
|
+
} catch (e) {
|
|
391
|
+
o.push({
|
|
392
|
+
error: e,
|
|
393
|
+
phase: "entityRemoved",
|
|
394
|
+
entityId: t
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
let u = performance.now() - t;
|
|
344
398
|
this.onMessageTyped({
|
|
345
399
|
type: "run-complete",
|
|
346
400
|
generation: e.generation,
|
|
347
|
-
runTime:
|
|
401
|
+
runTime: u,
|
|
348
402
|
events: n,
|
|
349
403
|
systemEvents: r,
|
|
350
|
-
created: i
|
|
404
|
+
created: i,
|
|
405
|
+
errors: o
|
|
351
406
|
});
|
|
352
407
|
}
|
|
353
408
|
}
|
|
@@ -391,7 +446,12 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
391
446
|
else if (t.type === "grow-buffer-from-worker") this.world.addGrownBuffer(t.buffer);
|
|
392
447
|
else if (t.type === "run-complete") {
|
|
393
448
|
if (t.generation !== this.generation) return;
|
|
394
|
-
this.isRunning = !1, this.world.emit(`system-${this.name}-worker-finished`, t.runTime)
|
|
449
|
+
this.isRunning = !1, this.world.emit(`system-${this.name}-worker-finished`, t.runTime), t.errors.forEach(({ error: e, entityId: t, phase: n }) => {
|
|
450
|
+
this.onError(e, {
|
|
451
|
+
entityId: t,
|
|
452
|
+
phase: n
|
|
453
|
+
});
|
|
454
|
+
});
|
|
395
455
|
for (let e of Object.keys(t.systemEvents)) this.emit(e, t.systemEvents[e]);
|
|
396
456
|
t.events.forEach((e) => {
|
|
397
457
|
let t = this.world.getEntityByEid(e.entityId);
|
|
@@ -624,6 +684,9 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
624
684
|
addGrownBuffer(e) {
|
|
625
685
|
this.heap.buffers[e.bufferPosition] === void 0 && this.heap.addSharedBuffer(e), this.emit("grow-buffer", e);
|
|
626
686
|
}
|
|
687
|
+
get needsSpareBuffer() {
|
|
688
|
+
return this.systems.some((e) => e instanceof A && e.isWorkerThread && !!e.options.createsEntities);
|
|
689
|
+
}
|
|
627
690
|
async init() {
|
|
628
691
|
await Promise.all(this.systems.map((e) => e.init()).filter((e) => e instanceof Promise));
|
|
629
692
|
}
|
|
@@ -736,7 +799,7 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
736
799
|
runUpdate(e) {
|
|
737
800
|
if (this.playerTime += e, this.paused) return {};
|
|
738
801
|
let t = e;
|
|
739
|
-
e = this.timeScale * e, this.gameTime += e, this.processFreeBuffers();
|
|
802
|
+
e = this.timeScale * e, this.gameTime += e, this.processFreeBuffers(), this.needsSpareBuffer && this.heap.ensureSpareBuffer();
|
|
740
803
|
let n = null;
|
|
741
804
|
return this.systems.forEach((t) => {
|
|
742
805
|
let r = !0, i = !1, a = !1;
|
|
@@ -744,8 +807,12 @@ var m = Object.create, h = Object.defineProperty, g = Object.getOwnPropertyDescr
|
|
|
744
807
|
try {
|
|
745
808
|
r = t.shouldRun(), r && (i = t.update(e));
|
|
746
809
|
} catch (e) {
|
|
747
|
-
let
|
|
748
|
-
console.error(
|
|
810
|
+
let r = e;
|
|
811
|
+
console.error(r.message, r), a = !0, n = r, this.emit("system-error", {
|
|
812
|
+
system: t.name,
|
|
813
|
+
error: r,
|
|
814
|
+
phase: "run"
|
|
815
|
+
});
|
|
749
816
|
}
|
|
750
817
|
this.emit(`system-${t.name}-finished`, {
|
|
751
818
|
ran: i,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../node_modules/eventemitter3/index.js","../node_modules/eventemitter3/index.mjs","../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/entity-factory.ts","../src/world.ts","../src/actions/kill-entity.ts","../src/performance-timing.ts"],"sourcesContent":["'use strict';\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif ('undefined' !== typeof module) {\n module.exports = EventEmitter;\n}\n","import EventEmitter from './index.js'\n\nexport { EventEmitter }\nexport default EventEmitter\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { BaseComponent, ComponentDefinitionMap, ComponentMap, RegisteredComponentRegistry } from './component-definition';\nimport type { EntityComponent } from './entity-component';\n\nexport default class BaseEntity<C extends ComponentMap = ComponentMap, Cfg = any> extends EventEmitter {\n\treadonly eid: number;\n\tconfig?: Cfg;\n\n\tworld: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\t// entity is always present; game components are partial.\n\tcomponents: Partial<C> & { entity: EntityComponent } = {} as Partial<C> & { entity: EntityComponent };\n\n\t// `adoptEid`: build an empty shell around a pre-minted id (an entity a worker created off-thread), skipping the\n\t// automatic entity-component load - the caller (world.adoptEntity) loads the entity component and attaches the\n\t// worker-allocated blocks itself.\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C, Cfg>, config?: Cfg, adoptEid?: number) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.eid = adoptEid ?? world.allocateEid();\n\t\tif(adoptEid !== undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.loadComponent('entity', config ?? {}, false);\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, emitAdded = true): C[K] {\n\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\tconst memoryComponent = definition.memoryComponent;\n\t\tconst index = memoryComponent.create(definition.toBlock(config, this));\n\t\tconst component = definition.attach(this, memoryComponent, index);\n\t\t// A Component subclass already holds its block; only fetch one for a plain-object accessor that didn't.\n\t\t(component as BaseComponent).block ??= memoryComponent.getBlock(index);\n\t\t(this.components as Partial<C>)[name] = component;\n\t\tif(emitAdded) {\n\t\t\tthis.emit('component-added', name, component);\n\t\t}\n\n\t\treturn component;\n\t}\n\t// Builds an accessor over an existing block (allocated + written by a worker) instead of creating a new one - the\n\t// adopt half of loadComponent, without the create.\n\tattachComponent<K extends keyof C>(name: K, index: number): C[K] {\n\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\tconst component = definition.attach(this, definition.memoryComponent, index);\n\t\t(component as BaseComponent).block ??= definition.memoryComponent.getBlock(index);\n\t\t(this.components as Partial<C>)[name] = component;\n\t\treturn component;\n\t}\n\tremoveComponent<K extends keyof C>(name: K) {\n\t\tconst component = (this.components as Partial<C>)[name];\n\t\tif(component) {\n\t\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\t\tthis.world.deferComponentMemoryFree(definition.memoryComponent, component.index, definition.free ? () => definition.free!(component) : undefined);\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(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\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tconst components = this.components as Partial<C>;\n\t\tfor(let name of Object.keys(components) as Array<keyof C>) {\n\t\t\tconst definition = registry[name];\n\t\t\tconst component = components[name];\n\t\t\tif(component) {\n\t\t\t\tthis.world.deferComponentMemoryFree(definition.memoryComponent, component.index, definition.free ? () => definition.free!(component) : undefined);\n\t\t\t}\n\t\t}\n\t}\n\n\tload(config: Cfg) {\n\t\tconst props = config as Record<string, unknown>;\n\t\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tfor(let name of Object.keys(registry) as Array<keyof C>) {\n\t\t\tif(name === 'entity') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst definition = registry[name];\n\t\t\tif(definition.loadInFinishLoading) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(definition.loadProperties.some(prop => prop in props)) {\n\t\t\t\tthis.loadComponent(name, config, false);\n\t\t\t}\n\t\t}\n\n\t\tthis.config = config;\n\t}\n\tsave(): Cfg {\n\t\tconst config: { [key: string]: any } = {};\n\n\t\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tconst components = this.components as Partial<C>;\n\t\tfor(let name of Object.keys(components) as Array<keyof C>) {\n\t\t\tconst definition = registry[name];\n\t\t\tconst component = components[name];\n\t\t\tif(definition.save && component) {\n\t\t\t\tObject.assign(config, definition.save(component));\n\t\t\t}\n\t\t}\n\n\t\treturn config as Cfg;\n\t}\n\t// Second pass once every entity in a load batch exists; loads the deferred (loadInFinishLoading)\n\t// components load skipped. Overrides should call super.\n\tfinishLoading() {\n\t\tconst config = this.config;\n\t\tif(!config) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst props = config as Record<string, unknown>;\n\t\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tfor(let name of Object.keys(registry) as Array<keyof C>) {\n\t\t\tif(name === 'entity') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst definition = registry[name];\n\t\t\tif(definition.loadInFinishLoading && definition.loadProperties.some(prop => prop in props)) {\n\t\t\t\tthis.loadComponent(name, config, false);\n\t\t\t}\n\t\t}\n\t}\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\n\n// Base system: runs on an optional fixed timestep (deltaBetweenRuns), driven by BaseWorld#update.\nexport default abstract class System<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\tworld: BaseWorld<ComponentDefinitionMap, C>;\n\tname: string;\n\tcurrentDelta: number = 0;\n\tdeltaBetweenRuns: number;\n\tfirstRun: boolean;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: SystemConfig = { name: 'System' }) {\n\t\tsuper();\n\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\t// Called once the world's entities all exist: the point a system hands its startup data off (see ComponentSystem).\n\tfinishLoading(): void | Promise<void> {}\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// Carry the remainder so a run that overshoots its timestep doesn't drift the next one later.\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\t\t\tthis.onRunFinished();\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\t// Marks one run as fully applied. Synchronous systems finish inside update(); subclasses whose work is\n\t// deferred (spread across frames, or off-thread) override this and call it at their real completion point.\n\tprotected onRunFinished() {\n\t\tthis.world.notifySystemRunCompleted(this);\n\t}\n\t// True while a run is still in progress between update() calls (a worker round-trip, or an iteration spread\n\t// across frames). Used by the world to keep waiting on a system that is mid-run over memory it may free.\n\tisCurrentlyRunning(): boolean {\n\t\treturn false;\n\t}\n\t// Resolves once any in-flight run has finished, so the world's clear() knows nothing is still reading memory\n\twaitForRunToComplete(): void | Promise<void> {}\n\n\tshouldRun(): boolean {\n\t\treturn true;\n\t}\n\n\tdestroy() {\n\t\tthis.removeAllListeners();\n\t}\n}\n\nexport interface SystemConfig {\n\tname: string\n\tdeltaBetweenRuns?: number\n\tfirstRun?: boolean\n}\n","import type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\nimport System, { type SystemConfig } from './system';\n\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<ComponentDefinitionMap, 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\t\t\tif(!this.remainingInstancesToRun.length) {\n\t\t\t\tthis.onRunFinished();\n\t\t\t}\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\t// A run that overflowed onto a later frame isn't finished yet; only count it once the queue drains (handled\n\t// by update() when it empties remainingInstancesToRun).\n\tprotected onRunFinished() {\n\t\tif(this.remainingInstancesToRun.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.onRunFinished();\n\t}\n\tisCurrentlyRunning(): boolean {\n\t\treturn this.remainingInstancesToRun.length > 0;\n\t}\n\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 { ComponentDefinitionMap, ComponentMap } from '../component-definition';\nimport IterableSystem, { type IterableSystemConfig } from './iterable-system';\n\n// Iterates the entities owning a given set of components on the main thread; membership tracks world events.\nexport default abstract class EntitySystem<C extends ComponentMap, T extends BaseEntity<C> = BaseEntity<C>> extends IterableSystem<C, T> {\n\tentities: Map<number, T> = new Map();\n\toptions: EntitySystemConfig<C>;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, 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\tconst iterables: Array<T> = [];\n\t\tthis.entities.forEach(entity => {\n\t\t\tif(!entity.components.entity.dead) {\n\t\t\t\titerables.push(entity);\n\t\t\t}\n\t\t});\n\n\t\treturn iterables;\n\t}\n\tupdateIterable(entity: T, elapsedTime: number): void {\n\t\tif(entity.components.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.components.entity.isStatic;\n\t}\n\tisEntityInSystem(entity: BaseEntity<C>) {\n\t\treturn this.entities.has(entity.eid);\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.set(entity.eid, 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\tthis.entities.delete(entity.eid);\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.size > 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 for the main-thread fallback. Loose params: this mirrors the DOM Worker boundary.\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 { applyQueryDelta } from './apply-query-delta';\nimport type ComponentWorkerMessage from './component-worker-message';\nimport type { EntityEvent, SystemEvents } from './component-worker-message';\nimport type BaseWorld from '../../world';\nimport type { ComponentDefinitionMap, ComponentMap, RegisteredComponentRegistry } from '../../component-definition';\nimport type {\n\tComponentSystemCallbacks, ComponentSystemWorld, EntityQueryComponents, EntityUpdateComponents,\n\tEntityUpdateFunction, QueryDelta, UpdateEntityConfigObject, WorkerAllocator, WorkerCreatedEntity,\n} from '../component-system';\nimport { buildWorkerEntity, type WorkerCreateRegistry } from '../../actions/build-worker-entity';\n\n// Main-thread fallback that runs the update function synchronously, mirroring the real worker's behavior.\nexport default class ComponentWebWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld, D = unknown> extends WebWorker {\n\tprivate updateFunction: EntityUpdateFunction<C, T, W, D>;\n\tprivate entities: Array<UpdateEntityConfigObject<T>> = [];\n\tprivate queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\t// Mirrors createComponentWorker: updateFunction.init's result, merged onto `world` each run.\n\tprivate worldExtension: Partial<W> | undefined;\n\t// Running on the main thread, this shares the world (its string cache, registry pools, eid counter) directly.\n\tprivate world: BaseWorld<ComponentDefinitionMap, C>;\n\tprivate allocator: WorkerAllocator;\n\tprivate createsEntities: boolean;\n\n\tconstructor(updateFunction: EntityUpdateFunction<C, T, W, D>, world: BaseWorld<ComponentDefinitionMap, C>, createsEntities = false) {\n\t\tsuper();\n\t\tthis.updateFunction = updateFunction;\n\t\tthis.world = world;\n\t\tthis.createsEntities = createsEntities;\n\t\tconst registry = world.registry as RegisteredComponentRegistry<C>;\n\t\tthis.allocator = {\n\t\t\tallocateEid: () => world.allocateEid(),\n\t\t\tallocateComponentBlock: (name, values) => registry[name as keyof C].memoryComponent.create(values),\n\t\t};\n\t}\n\n\tpostMessage(message: ComponentWorkerMessage<W, D>): void {\n\t\tif(message.type === 'init') {\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'init-complete',\n\t\t\t});\n\t\t} else if(message.type === 'load') {\n\t\t\tthis.worldExtension = this.updateFunction.init?.(message.data) ?? undefined;\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'reset') {\n\t\t\t// Drop the persistent lists so a reused world starts empty; worldExtension is refreshed by the next load.\n\t\t\tthis.entities = [];\n\t\t\tthis.queryEntities = {};\n\t\t} else if(message.type === 'run') {\n\t\t\tif(this.worldExtension) {\n\t\t\t\tObject.assign(message.world, this.worldExtension);\n\t\t\t}\n\t\t\tmessage.world.getString = (pointer: number) => this.world.constantStrings.getString(pointer) ?? '';\n\t\t\tmessage.world.allocate = this.allocator;\n\t\t\tif(this.createsEntities) {\n\t\t\t\tconst registry: WorkerCreateRegistry = this.world.registry;\n\t\t\t\tmessage.world.buildEntityDescriptor = config => buildWorkerEntity(config, this.world.factory.configs, registry, this.allocator);\n\t\t\t}\n\t\t\t// Timed like the real worker so a forceMainThread system reports a real run cost, not zero.\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<EntityEvent> = [];\n\t\t\tlet systemEvents: SystemEvents = {};\n\t\t\tlet createdEntities: Array<WorkerCreatedEntity> = [];\n\n\t\t\tthis.entities = applyQueryDelta(this.entities, message.entities as QueryDelta<T>);\n\n\t\t\tlet queries: EntityQueryComponents<C> = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, delta]) => {\n\t\t\t\tconst list = applyQueryDelta(this.queryEntities[queryKey] ?? [], delta as QueryDelta<T>);\n\t\t\t\tthis.queryEntities[queryKey] = list;\n\t\t\t\tqueries[queryKey] = list;\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\temitEntityEvent(entityId: number, event: string, ...args: Array<unknown>) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\targs,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\temitSystemEvent(event: string, entityId: number) {\n\t\t\t\t\t(systemEvents[event] ?? (systemEvents[event] = [])).push(entityId);\n\t\t\t\t},\n\t\t\t\tentityDied(entityId: number) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'death',\n\t\t\t\t\t\targs: [],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tcreateEntity(entity: WorkerCreatedEntity) {\n\t\t\t\t\tcreatedEntities.push(entity);\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, this.entities, queries, callbacks);\n\t\t\t}\n\t\t\tthis.entities.forEach(entity => {\n\t\t\t\tthis.updateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t});\n\n\t\t\tif(this.updateFunction.entityRemoved) {\n\t\t\t\tfor(let entityId of message.entities.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\tconst runTime = performance.now() - start;\n\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\tgeneration: message.generation,\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tsystemEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t});\n\t\t}\n\t}\n\n\tonMessageTyped(message: ComponentWorkerMessage<W, D>) {\n\t\tthis.onmessage({\n\t\t\tdata: message,\n\t\t});\n\t}\n}\n","import type { GrowBufferData } from '@daneren2005/shared-memory-objects/memory-heap';\nimport type BaseWorld from '../world';\nimport type BaseEntity from '../entity';\nimport type { BaseComponent, ComponentDefinitionMap, 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. Uses getWorker() when\n// Web Workers + SharedArrayBuffer exist, else falls back to ComponentWebWorker on the main thread. No game\n// concepts; games inject per-run data via addDataToWorld.\nexport default abstract class ComponentSystem<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n> extends System<C> {\n\tentities: Map<number, BaseEntity<C>> = new Map();\n\toptions: ComponentSystemConfig<C, T, W, D>;\n\n\tworker: Worker | ComponentWebWorker<C, T, W, D>;\n\tisWorkerThread: boolean;\n\n\tprivate initialized = false;\n\tprivate initPromise: Resolvable | null = null;\n\tprivate loadingPromise: Resolvable | null = null;\n\tprivate runCompletePromise: Resolvable | null = null;\n\tprivate isRunning = false;\n\t// Bumped by clear(); checked on each event to make certain we are dealing with the correct world\n\tprivate generation = 0;\n\tprivate queryEntities: { [key: string]: Map<number, BaseEntity<C>> } = {};\n\t// Membership changes since the last run(), flushed each run as a delta so a steady-state run sends empty\n\t// arrays rather than re-transmitting every eid. The worker applies these to its own list (see applyQueryDelta).\n\tprivate queryDeltas: { [key: string]: MembershipDelta<C> } = {};\n\n\taddDataToWorld?(world: W): void;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: ComponentSystemConfig<C, T, W, D>) {\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] = new Map();\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\t// Forward heap growth so the worker's reconstructed heap can resolve pointers into new buffers.\n\t\t\tworld.on('grow-buffer', (buffer: GrowBufferData) => {\n\t\t\t\tthis.worker.postMessage({ type: 'grow-buffer', buffer });\n\t\t\t});\n\t\t} else {\n\t\t\tthis.worker = new ComponentWebWorker(options.updateFunction, world, !!options.createsEntities);\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 === 'init-complete') {\n\t\t\t\tthis.initialized = true;\n\t\t\t\tif(this.initPromise) {\n\t\t\t\t\tthis.initPromise.resolve();\n\t\t\t\t\tthis.initPromise = null;\n\t\t\t\t}\n\t\t\t} else if(message.type === 'loaded') {\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 === 'grow-buffer-from-worker') {\n\t\t\t\t// A buffer this worker grew while allocating: adopt into the main heap and fan out to sibling workers.\n\t\t\t\tthis.world.addGrownBuffer(message.buffer);\n\t\t\t} else if(message.type === 'run-complete') {\n\t\t\t\t// A reply from a run that started before a clear(): the world it ran over is gone, so drop it whole.\n\t\t\t\tif(message.generation !== this.generation) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tthis.world.emit(`system-${this.name}-worker-finished`, message.runTime);\n\n\t\t\t\t// Before the per-entity events: an entity killed this run is still in the world here, since `death`\n\t\t\t\t// is dispatched below and removes it.\n\t\t\t\tfor(const event of Object.keys(message.systemEvents)) {\n\t\t\t\t\tthis.emit(event, message.systemEvents[event]);\n\t\t\t\t}\n\n\t\t\t\tmessage.events.forEach(event => {\n\t\t\t\t\t// Look up on the world, not the query cache, so events for sub-query-only entities still route.\n\t\t\t\t\tconst entity = this.world.getEntityByEid(event.entityId);\n\t\t\t\t\tif(!entity) {\n\t\t\t\t\t\tconsole.warn(`${this.name}-event ${event.event}: 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\n\t\t\t\t// After deaths, so an entity created this run isn't immediately removed. Adopts the blocks the worker\n\t\t\t\t// already allocated + wrote, rather than re-creating them.\n\t\t\t\tmessage.created.forEach(descriptor => {\n\t\t\t\t\tthis.world.adoptEntity(descriptor);\n\t\t\t\t});\n\n\t\t\t\tthis.world.emit(`system-${this.name}-worker-events-finished`, message.runTime);\n\t\t\t\tthis.world.notifySystemRunCompleted(this);\n\n\t\t\t\tif(this.runCompletePromise) {\n\t\t\t\t\tthis.runCompletePromise.resolve();\n\t\t\t\t\tthis.runCompletePromise = null;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage<W, D> = {\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.initialized) {\n\t\t\treturn;\n\t\t} else if(this.initPromise) {\n\t\t\treturn this.initPromise.promise;\n\t\t}\n\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\tthis.initPromise = {\n\t\t\tpromise,\n\t\t\tresolve,\n\t\t};\n\t\treturn promise;\n\t}\n\n\t// Sends the init data over and runs the update function's own init in the worker\n\tfinishLoading(): Promise<void> {\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\t// Assigned before posting: the main-thread fallback replies synchronously from inside postMessage.\n\t\tthis.loadingPromise = {\n\t\t\tpromise,\n\t\t\tresolve,\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage<W, D> = {\n\t\t\ttype: 'load',\n\t\t\tdata: this.options.getInitData?.(),\n\t\t\t// Only a real worker needs the buffers to rebuild a heap, plus the pools + eid counter to allocate off-thread.\n\t\t\theap: this.isWorkerThread ? this.world.heap.getSharedMemory() : undefined,\n\t\t\tsharedMemory: this.isWorkerThread ? this.world.getSharedComponentMemory() : undefined,\n\t\t\t// Factory templates only go to workers that create entities.\n\t\t\tfactoryConfigs: this.isWorkerThread && this.options.createsEntities ? this.world.factory.configs : undefined,\n\t\t};\n\t\tthis.worker.postMessage(message);\n\n\t\treturn promise;\n\t}\n\n\t// Un-initializes the system so its world can be reused\n\tclear() {\n\t\tsuper.clear();\n\n\t\tif(this.isRunning) {\n\t\t\tif(!this.runCompletePromise) {\n\t\t\t\tconst { promise, resolve } = Promise.withResolvers<void>();\n\t\t\t\tthis.runCompletePromise = { promise, resolve };\n\t\t\t}\n\t\t}\n\t\tthis.isRunning = false;\n\t\tthis.generation++;\n\n\t\tthis.entities.clear();\n\t\tObject.values(this.queryEntities).forEach(list => list.clear());\n\t\tthis.queryDeltas = {};\n\n\t\tconst message: ComponentWorkerMessage = { type: 'reset' };\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tupdate(elapsedTime: number): boolean {\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\t// A run finishes off-thread, not when update() returns; completedRuns is bumped on the worker's run-complete.\n\tprotected onRunFinished() {}\n\tisCurrentlyRunning(): boolean {\n\t\treturn this.isRunning;\n\t}\n\twaitForRunToComplete(): void | Promise<void> {\n\t\tif(!this.isRunning) {\n\t\t\treturn;\n\t\t}\n\t\tif(!this.runCompletePromise) {\n\t\t\tconst { promise, resolve } = Promise.withResolvers<void>();\n\t\t\tthis.runCompletePromise = { promise, resolve };\n\t\t}\n\t\treturn this.runCompletePromise.promise;\n\t}\n\trun(elapsedTime: number): void {\n\t\tconst world = {\n\t\t\tgameTime: this.world.gameTime,\n\t\t\telapsedTime,\n\t\t} as W;\n\t\tthis.addDataToWorld?.(world);\n\n\t\tthis.isRunning = true;\n\t\tlet entities = this.buildQueryDelta(MAIN_QUERY_NAME, this.options);\n\t\tlet queries: { [key: string]: QueryDelta<T> } = {};\n\t\tObject.entries(this.options.queries ?? {}).forEach(([queryKey, query]) => {\n\t\t\tqueries[queryKey] = this.buildQueryDelta(queryKey, query);\n\t\t});\n\t\tlet message: ComponentWorkerMessage<W> = {\n\t\t\ttype: 'run',\n\t\t\tgeneration: this.generation,\n\t\t\tworld,\n\t\t\tentities,\n\t\t\tqueries,\n\t\t};\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tprivate buildQueryDelta(queryName: string, query: ComponentSystemQuery<C>): QueryDelta<T> {\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tconst added: Array<UpdateEntityConfigObject<T>> = [];\n\t\tdelta.added.forEach(entity => {\n\t\t\tadded.push({\n\t\t\t\tentityId: entity.eid,\n\t\t\t\tcomponents: this.buildComponents(entity, query),\n\t\t\t});\n\t\t});\n\t\tconst removed = Array.from(delta.removed);\n\t\tthis.queryDeltas[queryName] = { added: new Set(), removed: new Set() };\n\n\t\treturn { added, removed };\n\t}\n\tprivate buildComponents(entity: BaseEntity<C>, query: ComponentSystemQuery<C>): T {\n\t\tconst components = {} as T;\n\t\t[\n\t\t\t...query.required,\n\t\t\t...query.optional ?? [],\n\t\t].forEach(componentName => {\n\t\t\t// Reuse the view cached on the accessor at attach: getBlock allocates a fresh subarray every call and an\n\t\t\t// entity joins many systems, so re-looking it up here per system was a measurable spawn-time cost.\n\t\t\tconst block = entity.components[componentName]?.block;\n\t\t\tif(block) {\n\t\t\t\tcomponents[componentName] = block as T[typeof componentName];\n\t\t\t}\n\t\t});\n\n\t\treturn components;\n\t}\n\n\tisEntityInSystem(entity: BaseEntity<C>) {\n\t\treturn this.entities.has(entity.eid);\n\t}\n\tprivate matchesQuery(entity: BaseEntity<C>, query: ComponentSystemQuery<C>): boolean {\n\t\tif(entity.components.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 getQueryDelta(queryName: string): MembershipDelta<C> {\n\t\tlet delta = this.queryDeltas[queryName];\n\t\tif(!delta) {\n\t\t\tdelta = this.queryDeltas[queryName] = { added: new Set(), removed: new Set() };\n\t\t}\n\n\t\treturn delta;\n\t}\n\t// A pending removal this same frame is cancelled, so the net effect is a re-send rather than remove+add churn.\n\tprivate markAdded(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tdelta.removed.delete(entity.eid);\n\t\tdelta.added.add(entity);\n\t}\n\tprivate markRemoved(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tif(delta.added.delete(entity)) {\n\t\t\treturn;\n\t\t}\n\n\t\tdelta.removed.add(entity.eid);\n\t}\n\tprivate updateEntityList(queryName: string, list: Map<number, BaseEntity<C>>, entity: BaseEntity<C>, shouldInclude: boolean) {\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tif(shouldInclude) {\n\t\t\tlist.set(entity.eid, entity);\n\t\t\tthis.markAdded(delta, entity);\n\t\t} else if(list.delete(entity.eid)) {\n\t\t\tthis.markRemoved(delta, entity);\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(MAIN_QUERY_NAME, 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] = new Map());\n\t\t\tthis.updateEntityList(queryName, queryList, entity, this.matchesQuery(entity, query));\n\t\t});\n\n\t\treturn shouldAddToMain;\n\t}\n\tremoveEntity(entity: BaseEntity<C>) {\n\t\tthis.updateEntityList(MAIN_QUERY_NAME, this.entities, entity, false);\n\t\tObject.entries(this.queryEntities).forEach(([queryName, list]) => {\n\t\t\tthis.updateEntityList(queryName, list, entity, false);\n\t\t});\n\t}\n\n\t// Re-evaluates every entity's membership against the current queries. Needed when a `filter` closes over mutable\n\t// state (e.g. a scope keyed on which group is active) and that state changes with no entity event to react to\n\trecheckMembership() {\n\t\tthis.world.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.size > 0;\n\t}\n\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tif('terminate' in this.worker) {\n\t\t\tthis.worker.terminate();\n\t\t}\n\t}\n}\n\ninterface Resolvable {\n\tpromise: Promise<void>\n\tresolve: (value: void | PromiseLike<void>) => void\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>, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentityId: number,\n\tcomponents: T,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\nexport type EntityUpdateFunction<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n> = EntityUpdateFunctionImpl<C, T, W> & {\n\tpreRun?: EntityUpdatePreRunFunction<C, T, W>\n\tentityRemoved?: EntityRemovedFunction<C, W>\n\tinit?: EntityUpdateInitFunction<W, D>\n};\nexport type EntityUpdateInitFunction<W extends ComponentSystemWorld = ComponentSystemWorld, D = unknown> = (data: D | undefined) => Partial<W> | void;\nexport type EntityUpdatePreRunFunction<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentities: Array<UpdateEntityConfigObject<T>>,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\nexport type EntityRemovedFunction<C extends ComponentMap = ComponentMap, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentityId: number,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => 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\nexport interface QueryDelta<T extends EntityUpdateComponents = EntityUpdateComponents> {\n\tadded: Array<UpdateEntityConfigObject<T>>\n\tremoved: Array<number>\n}\n// Sets so queuing can check for an already-queued or opposite change without scanning a growing array.\ninterface MembershipDelta<C extends ComponentMap> {\n\tadded: Set<BaseEntity<C>>\n\tremoved: Set<number>\n}\n\n// Low-level off-thread allocation primitives, injected onto the worker `world` each run. `allocateEid` mints a\n// heap-unique id; `allocateComponentBlock` pushes a block into a component's shared pool and returns its index.\n// These are the foundation a future worker-side createEntity builds on (allocate + write blocks, then report the\n// eid/indexes back for the main thread to adopt).\nexport interface WorkerAllocator {\n\tallocateEid(): number\n\tallocateComponentBlock(name: string, values: Array<number>): number\n}\n\nexport interface ComponentSystemWorld {\n\tgameTime: number\n\telapsedTime: number\n\tgetString(pointer: number): string\n\tallocate?: WorkerAllocator\n\t// Injected each run on a system registered with createsEntities: builds a WorkerCreatedEntity descriptor from a\n\t// factory config (merges the type's template, allocates + writes each component's block). Drives createEntityWorker.\n\tbuildEntityDescriptor?(config: WorkerCreateEntityConfig): WorkerCreatedEntity\n}\n// What a game passes to createEntityWorker: a factory-style config - the entity `type` plus any overrides layered\n// over that type's factory template. The worker merges template + overrides, then allocates + writes each triggered\n// component's block off-thread via the component's toBlock(config). The \"entity\" component is built on the main\n// thread when the descriptor is adopted, since interning the type is main-thread-only.\nexport type WorkerCreateEntityConfig = { type: string } & { [key: string]: unknown };\n// The result reported back on run-complete: the minted id plus, per game component, the pool index the worker\n// allocated. world.adoptEntity turns this into a real BaseEntity.\nexport interface WorkerCreatedEntity {\n\teid: number\n\ttype: string\n\tisStatic?: boolean\n\tcomponents: { [name: string]: number }\n}\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\t// Args are structured-cloned, so plain values only.\n\temitEntityEvent(entityId: number, event: string, ...args: Array<unknown>): void\n\t// Emitted **on the system** with all its ids in one array. The allocation-free path for something that\n\t// happens to most entities every run; carries no args (values are already in shared memory).\n\temitSystemEvent(event: string, entityId: number): void\n\tentityDied(entityId: number): void\n\tcreateEntity(entity: WorkerCreatedEntity): 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<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n> extends SystemConfig, ComponentSystemQuery<C> {\n\tupdateFunction: EntityUpdateFunction<C, T, W, D>\n\tgetWorker: () => Worker\n\tforceMainThread?: boolean\n\tgetInitData?: () => D\n\t// Opt in to worker-side entity creation (createEntityWorker). When set, the factory configs are shipped to this\n\t// system's worker on load so it can merge templates; the worker entry must also pass the component registry to\n\t// createComponentWorker so it has each component's toBlock(). Only systems that create entities need either.\n\tcreatesEntities?: boolean\n\n\tqueries?: { [key: string]: ComponentSystemQuery<C> }\n}\n\nexport type { BaseComponent };\n","import BaseEntity from './entity';\nimport type BaseWorld from './world';\nimport type { ComponentDefinitionMap, ComponentMap } from './component-definition';\n\n// Maps an entity `type` to a base (template) config; loading layers the caller's config over it.\nexport default class EntityFactory<C extends ComponentMap = ComponentMap, Cfg = any> {\n\tworld!: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\tconfigs: { [type: string]: Cfg };\n\n\tconstructor(configs: { [type: string]: Cfg } = {}) {\n\t\tthis.configs = configs;\n\t}\n\n\tregister(type: string, config: Cfg) {\n\t\tthis.configs[type] = config;\n\t}\n\n\tgetConfig(config: Cfg): Cfg {\n\t\tconst type = (config as { type?: string } | undefined)?.type;\n\t\tconst base = type ? this.configs[type] : undefined;\n\t\treturn base ? { ...base, ...config } : config;\n\t}\n\n\tloadEntity(config: Cfg, created = true): BaseEntity<C, Cfg> {\n\t\tconst entity = this.createEntity(this.getConfig(config));\n\t\treturn this.world.addEntity(entity, created);\n\t}\n\n\tprotected createEntity(config: Cfg): BaseEntity<C, Cfg> {\n\t\treturn new BaseEntity<C, Cfg>(this.world, config);\n\t}\n}\n","import { EventEmitter } from 'eventemitter3';\nimport MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type { GrowBufferData } from '@daneren2005/shared-memory-objects/memory-heap';\nimport type AllocatedMemory from '@daneren2005/shared-memory-objects/allocated-memory';\nimport type { SharedAllocatedMemory } from '@daneren2005/shared-memory-objects/allocated-memory';\nimport type { SharedPoolMemory } from '@daneren2005/shared-memory-objects/shared-pool';\nimport { MAX_BYTE_OFFSET_LENGTH } from '@daneren2005/shared-memory-objects/utils/pointer';\nimport MemoryComponent from './memory-component';\nimport ConstantStringCache from './constant-string-cache';\nimport BaseEntity from './entity';\nimport type System from './systems/system';\nimport EntitySystem from './systems/entity-system';\nimport ComponentSystem from './systems/component-system';\nimport type { WorkerCreatedEntity } from './systems/component-system';\nimport type {\n\tBaseComponent, ComponentDefinitionMap, ComponentMap, ComponentRegistry, ComponentsOf,\n\tEntityConfigOf, RegisteredComponentDefinition, RegisteredComponentRegistry,\n} from './component-definition';\nimport { entityDefinition, type EntityComponent } from './entity-component';\nimport EntityFactory from './entity-factory';\n\nconst DEFAULT_HEAP_SIZE = MAX_BYTE_OFFSET_LENGTH;\nconst FREE_BUFFER_STUCK_MS = 10000;\n\ninterface DeferredComponentFree {\n\tmemoryComponent: MemoryComponent\n\tindex: number\n\t// The definition's free hook, deferred to fire alongside the block free rather than the instant the entity dies.\n\tfree?: () => void\n}\n// A batch of component blocks queued to be freed, plus the systems that must each finish a run before it is safe to free them\ninterface ComponentFreeBuffer<C extends ComponentMap> {\n\tfrees: Array<DeferredComponentFree>\n\twaitingSystems: Set<System<C>>\n\twaitElapsed: number\n}\n\nexport interface WorldOptions<C extends ComponentMap = ComponentMap, Cfg = any> {\n\theapSize?: number\n\tfactory?: EntityFactory<C, Cfg>\n}\n\nexport interface WorldConfig<Cfg = any> {\n\tentities: Array<Cfg>\n\tgameTime?: number\n\tplayerTime?: number\n\ttimeScale?: number\n}\n\n// Shipped to a worker so it can reconstruct handles over this world's shared state (see getSharedComponentMemory).\nexport interface WorldSharedMemory {\n\tcomponents: { [name: string]: SharedPoolMemory }\n\teidCounter: SharedAllocatedMemory\n}\n\nexport default class BaseWorld<\n\tR extends ComponentDefinitionMap = ComponentDefinitionMap,\n\tC extends ComponentMap = ComponentsOf<R>,\n\tCfg = EntityConfigOf<R>,\n> extends EventEmitter {\n\theap: MemoryHeap;\n\t// Interns entity type names (and any other constant strings) in the heap\n\tconstantStrings: ConstantStringCache;\n\t// Single heap-backed counter every thread bumps atomically, so eids stay unique whether an entity is created on\n\t// the main thread or inside a worker.\n\tprivate eidCounter: AllocatedMemory;\n\tregistry: RegisteredComponentRegistry<C> & { entity: RegisteredComponentDefinition<EntityComponent> };\n\tfactory: EntityFactory<C, Cfg>;\n\n\t// Keyed by eid: entities leave from the middle one at a time (every death), so a Map deletes in constant\n\t// time while still iterating in insertion order, preserving load/save order.\n\tentities: Map<number, BaseEntity<C, Cfg>> = new Map();\n\tsystems: Array<System<C>> = [];\n\n\tgameTime = 0;\n\t// Keeps advancing while paused and is never scaled by timeScale (unlike gameTime).\n\tplayerTime = 0;\n\ttimeScale = 1;\n\tpaused = false;\n\tdestroyed = false;\n\t// True while the world has never been loaded into\n\tpristine = true;\n\n\t// Two rolling buffers of component blocks awaiting a safe free. New deferrals land in `next`; `active` is the\n\t// one currently waiting for its systems to each finish a run before its blocks can be reused\n\tprivate activeFreeBuffer: ComponentFreeBuffer<C> = { frees: [], waitingSystems: new Set(), waitElapsed: 0 };\n\tprivate nextFreeBuffer: ComponentFreeBuffer<C> = { frees: [], waitingSystems: new Set(), waitElapsed: 0 };\n\n\t// The entity component is added automatically, so it must not be part of the passed registry.\n\tconstructor(registry: R, options: WorldOptions<C, Cfg> = {}) {\n\t\tsuper();\n\n\t\tthis.heap = new MemoryHeap({ bufferSize: options.heapSize ?? DEFAULT_HEAP_SIZE });\n\t\tthis.constantStrings = new ConstantStringCache(this.heap);\n\t\tthis.eidCounter = this.heap.allocUI32(1);\n\t\t// A grown buffer must reach every worker's reconstructed heap so pointers into it still resolve.\n\t\tthis.heap.addOnGrowBufferHandlers((data: GrowBufferData) => this.emit('grow-buffer', data));\n\n\t\tconst inputRegistry = { ...registry, entity: entityDefinition } as ComponentRegistry<C> & { entity: typeof entityDefinition };\n\t\tconst registry_: Record<string, RegisteredComponentDefinition<BaseComponent>> = {};\n\t\tfor(let name of Object.keys(inputRegistry)) {\n\t\t\tconst definition = inputRegistry[name as keyof typeof inputRegistry];\n\t\t\tregistry_[name] = {\n\t\t\t\t...definition,\n\t\t\t\tmemoryComponent: new MemoryComponent(this.heap, definition.type, definition.size),\n\t\t\t};\n\t\t}\n\t\tthis.registry = registry_ as RegisteredComponentRegistry<C> & { entity: RegisteredComponentDefinition<EntityComponent> };\n\n\t\tthis.factory = options.factory ?? new EntityFactory<C, Cfg>();\n\t\tthis.factory.world = this;\n\t}\n\n\t// Returns a fresh, unique entity id. Backed by a heap atomic so a worker allocating an entity gets an id that can\n\t// never collide with one the main thread (or another worker) hands out. First id is 1, matching the old counter.\n\tallocateEid(): number {\n\t\treturn Atomics.add(this.eidCounter.data, 0, 1) + 1;\n\t}\n\t// Everything a worker needs to reconstruct handles over this world's shared state: one SharedPoolMemory per\n\t// registered component (so it can allocate/read blocks) plus the eid counter (so it can mint unique ids).\n\tgetSharedComponentMemory(): WorldSharedMemory {\n\t\tconst components: { [name: string]: SharedPoolMemory } = {};\n\t\tfor(let name of Object.keys(this.registry)) {\n\t\t\tcomponents[name] = this.registry[name as keyof typeof this.registry].memoryComponent.getSharedMemory();\n\t\t}\n\t\treturn {\n\t\t\tcomponents,\n\t\t\teidCounter: this.eidCounter.getSharedMemory(),\n\t\t};\n\t}\n\t// A buffer that was grown inside a worker: adopt it into the main heap (if not already present) and fan it out to\n\t// every other worker so their heaps can resolve pointers into it. The heap's BUFFER_COUNT is authoritative, so\n\t// re-adding an already-known position is a harmless overwrite of the same SharedArrayBuffer.\n\taddGrownBuffer(data: GrowBufferData) {\n\t\tif(this.heap.buffers[data.bufferPosition] === undefined) {\n\t\t\tthis.heap.addSharedBuffer(data);\n\t\t}\n\t\tthis.emit('grow-buffer', data);\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\tprivate finishLoadingSystems() {\n\t\treturn Promise.all(this.systems.map(system => system.finishLoading()).filter(promise => promise instanceof Promise));\n\t}\n\n\taddEntity(entity: BaseEntity<C, Cfg>, created = true): BaseEntity<C, Cfg> {\n\t\tthis.entities.set(entity.eid, entity);\n\t\tentity.world = this;\n\t\t// Any entity in the world means there is state to tear down on the next load/clear.\n\t\tthis.pristine = false;\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\tthis.emit('entity-added', entity);\n\t\t\tentity.on('death', () => {\n\t\t\t\tthis.onEntityDied(entity);\n\t\t\t});\n\t\t}\n\n\t\treturn entity;\n\t}\n\tloadEntity(config: Cfg, created = true): BaseEntity<C, Cfg> {\n\t\treturn this.factory.loadEntity(config, created);\n\t}\n\t// Materializes an entity a worker created off-thread (see createEntityWorker): the worker already minted the id and\n\t// allocated + wrote every game-component block, so this only builds the `entity` component on the main thread\n\t// (interning its type) and adopts each worker-allocated block by index, then wires it into the world like any new\n\t// entity. Adopted entities are always the base BaseEntity - the factory's per-type subclass/template is not applied.\n\tadoptEntity(descriptor: WorkerCreatedEntity): BaseEntity<C, Cfg> {\n\t\tconst entity = new BaseEntity<C, Cfg>(this, undefined, descriptor.eid);\n\t\tentity.loadComponent('entity', { type: descriptor.type, isStatic: descriptor.isStatic }, false);\n\t\tfor(let name of Object.keys(descriptor.components)) {\n\t\t\tentity.attachComponent(name, descriptor.components[name]);\n\t\t}\n\t\treturn this.addEntity(entity, true);\n\t}\n\t// Replaces the world's contents. Entities load with created = false so no finishLoading runs mid-batch;\n\t// finishLoading is called on each once the whole batch exists, so cross-entity dependencies can resolve.\n\tload(config: WorldConfig<Cfg>) {\n\t\t// A pristine world (fresh or just cleared) has nothing to tear down, so skip the per-system clear.\n\t\tif(!this.pristine) {\n\t\t\t// Iterate over a copy since removeEntity mutates `this.entities`.\n\t\t\tfor(let entity of Array.from(this.entities.values())) {\n\t\t\t\tthis.removeEntity(entity);\n\t\t\t}\n\t\t\tthis.systems.forEach(system => system.clear());\n\t\t\tthis.consolidateFreeBuffersForReload();\n\t\t}\n\n\t\t// Intern a constant string for every type the factory knows, so a worker can resolve any type - even one no\n\t\t// currently-loaded entity uses. Deduped, so the types actually loaded below cost nothing extra.\n\t\tfor(let type of Object.keys(this.factory.configs)) {\n\t\t\tthis.constantStrings.getOrCreate(type);\n\t\t}\n\n\t\tconst entities = config.entities.map(entityConfig => this.loadEntity(entityConfig, false));\n\t\tfor(let entity of entities) {\n\t\t\tentity.finishLoading();\n\t\t\tthis.emit('entity-added', entity);\n\t\t\tentity.on('death', () => {\n\t\t\t\tthis.onEntityDied(entity);\n\t\t\t});\n\t\t}\n\n\t\tthis.gameTime = config.gameTime ?? 0;\n\t\tthis.playerTime = config.playerTime ?? 0;\n\t\tthis.timeScale = config.timeScale ?? 1;\n\n\t\t// ComponentSystem re-sends its init data here.\n\t\tvoid this.finishLoadingSystems();\n\t}\n\tasync clear(): Promise<void> {\n\t\tif(this.pristine) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor(let entity of Array.from(this.entities.values())) {\n\t\t\tthis.removeEntity(entity);\n\t\t}\n\t\tthis.systems.forEach(system => system.clear());\n\t\tawait Promise.all(\n\t\t\tthis.systems\n\t\t\t\t.map(system => system.waitForRunToComplete())\n\t\t\t\t.filter(promise => promise instanceof Promise),\n\t\t);\n\t\tthis.freeAllPendingBuffers();\n\n\t\tthis.pristine = true;\n\t}\n\tremoveEntity(entity: BaseEntity<C, Cfg>) {\n\t\t// delete reports whether it was actually present, so a double-remove emits entity-removed only once.\n\t\tif(this.entities.delete(entity.eid)) {\n\t\t\tthis.emit('entity-removed', entity);\n\t\t}\n\n\t\tentity.deleteAllComponentMemory();\n\t}\n\tonEntityDied(entity: BaseEntity<C, Cfg>) {\n\t\tthis.removeEntity(entity);\n\t}\n\tgetEntityByEid(eid: number): BaseEntity<C, Cfg> | undefined {\n\t\treturn this.entities.get(eid);\n\t}\n\n\t// Queues a component block to be freed when all systems done using it, running the definition's free hook (if any)\n\t// at that same deferred point so a system still mid-run can't observe the resource being torn down early.\n\tdeferComponentMemoryFree(memoryComponent: MemoryComponent, index: number, free?: () => void) {\n\t\tthis.nextFreeBuffer.frees.push({ memoryComponent, index, free });\n\t}\n\t// A system finished a run; if the active buffer was waiting on it, drop it and, once nothing is left to wait\n\t// for, free the buffer. One completion is enough: the system is now done touching the block for that run, and\n\t// every later run applies the pending removed-delta before its update loop, so it can never process the freed\n\t// entity again.\n\tnotifySystemRunCompleted(system: System<C>) {\n\t\tif(this.activeFreeBuffer.waitingSystems.delete(system) && this.activeFreeBuffer.waitingSystems.size === 0) {\n\t\t\tthis.processFreeBuffers();\n\t\t}\n\t}\n\tprivate processFreeBuffers() {\n\t\t// Loop so a promoted buffer with no systems to wait for is freed the same tick rather than a frame later.\n\t\twhile(this.activeFreeBuffer.waitingSystems.size === 0) {\n\t\t\tif(this.activeFreeBuffer.frees.length > 0) {\n\t\t\t\tthis.performFrees(this.activeFreeBuffer);\n\t\t\t}\n\t\t\tif(this.nextFreeBuffer.frees.length === 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.promoteNextFreeBuffer();\n\t\t}\n\t}\n\tprivate promoteNextFreeBuffer() {\n\t\t// active is now empty (its frees were performed); swap roles and reuse it as the new next buffer.\n\t\tconst emptied = this.activeFreeBuffer;\n\t\tthis.activeFreeBuffer = this.nextFreeBuffer;\n\t\tthis.nextFreeBuffer = emptied;\n\n\t\tconst active = this.activeFreeBuffer;\n\t\tactive.waitElapsed = 0;\n\t\tactive.waitingSystems.clear();\n\t\tfor(let system of this.systems) {\n\t\t\t// Wait on a system if it will run (and so might pick up this block) or is already mid-run over memory we\n\t\t\t// may free. A system that is neither can't touch these blocks, so there's nothing to wait for.\n\t\t\tif(system.shouldRun() || system.isCurrentlyRunning()) {\n\t\t\t\tactive.waitingSystems.add(system);\n\t\t\t}\n\t\t}\n\t}\n\t// On reload every system was just cleared (its completedRuns reset and worker told to drop its lists), so the\n\t// old targets no longer apply. Collapse whatever was pending into `next` with a fresh (empty) active buffer\n\tprivate consolidateFreeBuffersForReload() {\n\t\tif(this.activeFreeBuffer.frees.length > 0) {\n\t\t\tthis.nextFreeBuffer.frees.push(...this.activeFreeBuffer.frees);\n\t\t\tthis.activeFreeBuffer.frees.length = 0;\n\t\t}\n\t\tthis.activeFreeBuffer.waitingSystems.clear();\n\t\tthis.activeFreeBuffer.waitElapsed = 0;\n\t}\n\t// Frees both buffers outright. Only safe once every system's in-flight run has finished (see clear()), since it\n\t// skips the per-system wait the update loop normally enforces.\n\tprivate freeAllPendingBuffers() {\n\t\tthis.performFrees(this.activeFreeBuffer);\n\t\tthis.performFrees(this.nextFreeBuffer);\n\t\tthis.activeFreeBuffer.waitingSystems.clear();\n\t\tthis.activeFreeBuffer.waitElapsed = 0;\n\t\tthis.nextFreeBuffer.waitingSystems.clear();\n\t\tthis.nextFreeBuffer.waitElapsed = 0;\n\t}\n\tprivate performFrees(buffer: ComponentFreeBuffer<C>) {\n\t\tfor(let deferred of buffer.frees) {\n\t\t\tdeferred.free?.();\n\t\t\tdeferred.memoryComponent.delete(deferred.index);\n\t\t}\n\t\tbuffer.frees.length = 0;\n\t}\n\tprivate checkFreeBufferTimeout(elapsedTime: number) {\n\t\tconst active = this.activeFreeBuffer;\n\t\tif(active.waitingSystems.size === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tactive.waitElapsed += elapsedTime;\n\t\tif(active.waitElapsed >= FREE_BUFFER_STUCK_MS) {\n\t\t\tconst stuck = Array.from(active.waitingSystems).map(system => system.name).join(', ');\n\t\t\tconsole.warn(`shared-memory-ecs: deferred component free waited over ${FREE_BUFFER_STUCK_MS}ms on system(s): ${stuck}; freeing anyway`);\n\t\t\tactive.waitingSystems.clear();\n\t\t\tthis.processFreeBuffers();\n\t\t}\n\t}\n\n\taddSystem<T extends System<C>>(system: T): T {\n\t\tthis.systems.push(system);\n\t\tthis.emit('system-added', 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\tthis.emit('system-added', 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\tconst [system] = this.systems.splice(index, 1);\n\t\t\tthis.emit('system-removed', system);\n\t\t}\n\t}\n\n\tupdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\tthis.emit('update-started', elapsedTime);\n\t\tconst result = this.runUpdate(elapsedTime);\n\t\tthis.emit('update-finished', elapsedTime);\n\n\t\treturn result;\n\t}\n\tprivate runUpdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\tthis.playerTime += elapsedTime;\n\t\tif(this.paused) {\n\t\t\treturn {};\n\t\t}\n\t\tconst unscaledElapsedTime = elapsedTime;\n\t\telapsedTime = this.timeScale * elapsedTime;\n\n\t\tthis.gameTime += elapsedTime;\n\n\t\t// Promote before running: a run this same update then counts toward the wait, instead of after it.\n\t\tthis.processFreeBuffers();\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\tthis.checkFreeBufferTimeout(unscaledElapsedTime);\n\n\t\treturn {\n\t\t\tlastSystemError,\n\t\t};\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t}\n\tresume() {\n\t\tthis.paused = false;\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, any>, 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 BaseEntity from '../entity';\n\n// Flags the entity dead in shared memory and emits `death`; BaseWorld listens for it to remove the entity.\nexport default function killEntity(entity: BaseEntity): void {\n\tentity.components.entity.dead = true;\n\tentity.emit('death');\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { ComponentDefinitionMap, ComponentMap } from './component-definition';\nimport type System from './systems/system';\n\nexport const DEFAULT_TICKS_BETWEEN_UPDATES = 1_000;\n\nexport interface TimingStats {\n\tavg: number\n\tmin: number\n\tmax: number\n\tsamples: number\n}\n\nexport interface SystemTimingStats {\n\tname: string\n\trun: TimingStats\n\tevents: TimingStats\n}\n\nexport interface PerformanceStats {\n\tupdate: TimingStats\n\tsystems: Array<SystemTimingStats>\n\tevents: TimingStats\n}\n\nexport interface PerformanceTimingOptions {\n\tticksBetweenUpdates?: number\n}\n\ninterface SystemTiming {\n\trun: Array<number>\n\tevents: Array<number>\n\t// -1 when no run is being dispatched.\n\teventStart: number\n\tonRunFinished: (runTime: number) => void\n\tonEventsFinished: () => void\n}\n\nconst EMPTY_TIMING: TimingStats = { avg: 0, min: 0, max: 0, samples: 0 };\n\n// An empty window reads as zeroes (not an infinite min) so a snapshot is always safe to render.\nfunction summarize(samples: Array<number>): TimingStats {\n\tif(!samples.length) {\n\t\treturn { ...EMPTY_TIMING };\n\t}\n\n\tlet total = 0;\n\tlet min = Infinity;\n\tlet max = 0;\n\tfor(let sample of samples) {\n\t\ttotal += sample;\n\t\tif(sample < min) {\n\t\t\tmin = sample;\n\t\t}\n\t\tif(sample > max) {\n\t\t\tmax = sample;\n\t\t}\n\t}\n\n\treturn {\n\t\tavg: total / samples.length,\n\t\tmin,\n\t\tmax,\n\t\tsamples: samples.length,\n\t};\n}\n\n// Watches a world and reports what it costs to run, driven off events the world emits. Emits `stats-updated`\n// every `ticksBetweenUpdates`; paused frames are skipped.\nexport default class PerformanceTiming<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\tworld: BaseWorld<ComponentDefinitionMap, C>;\n\tticksBetweenUpdates: number;\n\tstats: PerformanceStats = {\n\t\tupdate: { ...EMPTY_TIMING },\n\t\tsystems: [],\n\t\tevents: { ...EMPTY_TIMING },\n\t};\n\n\tprivate ticks = 0;\n\tprivate updateStart = 0;\n\tprivate updateTimes: Array<number> = [];\n\tprivate systemTimings = new Map<string, SystemTiming>();\n\tprivate destroyed = false;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: PerformanceTimingOptions = {}) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.ticksBetweenUpdates = options.ticksBetweenUpdates ?? DEFAULT_TICKS_BETWEEN_UPDATES;\n\n\t\tworld.on('update-started', this.onUpdateStarted);\n\t\tworld.on('update-finished', this.onUpdateFinished);\n\t\tworld.on('system-added', this.onSystemAdded);\n\t\tworld.on('system-removed', this.onSystemRemoved);\n\t\tworld.systems.forEach(system => this.trackSystem(system));\n\t}\n\n\tgetSystemStats(name: string): SystemTimingStats | undefined {\n\t\treturn this.stats.systems.find(system => system.name === name);\n\t}\n\n\treset() {\n\t\tthis.ticks = 0;\n\t\tthis.updateTimes = [];\n\t\tthis.systemTimings.forEach(timing => {\n\t\t\ttiming.run = [];\n\t\t\ttiming.events = [];\n\t\t\ttiming.eventStart = -1;\n\t\t});\n\t\tthis.stats = {\n\t\t\tupdate: { ...EMPTY_TIMING },\n\t\t\tsystems: [],\n\t\t\tevents: { ...EMPTY_TIMING },\n\t\t};\n\t}\n\n\tdestroy() {\n\t\tif(this.destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.destroyed = true;\n\n\t\tthis.world.off('update-started', this.onUpdateStarted);\n\t\tthis.world.off('update-finished', this.onUpdateFinished);\n\t\tthis.world.off('system-added', this.onSystemAdded);\n\t\tthis.world.off('system-removed', this.onSystemRemoved);\n\t\tArray.from(this.systemTimings.keys()).forEach(name => this.untrackSystem(name));\n\t\tthis.removeAllListeners();\n\t}\n\n\tprivate onUpdateStarted = () => {\n\t\tthis.updateStart = performance.now();\n\t};\n\n\tprivate onUpdateFinished = (elapsedTime: number) => {\n\t\tif(this.world.paused) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateTimes.push(performance.now() - this.updateStart);\n\n\t\tthis.ticks += elapsedTime;\n\t\tif(this.ticks >= this.ticksBetweenUpdates) {\n\t\t\tthis.recalculate();\n\t\t}\n\t};\n\n\tprivate onSystemAdded = (system: System<C>) => {\n\t\tthis.trackSystem(system);\n\t};\n\n\tprivate onSystemRemoved = (system: System<C>) => {\n\t\tthis.untrackSystem(system.name);\n\t};\n\n\t// The gap between `-worker-finished` (before events dispatch) and `-worker-events-finished` (after) is what\n\t// that run cost this thread. Both fire for the main-thread fallback too.\n\tprivate trackSystem(system: System<C>) {\n\t\tif(this.systemTimings.has(system.name)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst timing: SystemTiming = {\n\t\t\trun: [],\n\t\t\tevents: [],\n\t\t\teventStart: -1,\n\t\t\tonRunFinished: (runTime: number) => {\n\t\t\t\ttiming.run.push(runTime);\n\t\t\t\ttiming.eventStart = performance.now();\n\t\t\t},\n\t\t\tonEventsFinished: () => {\n\t\t\t\tif(timing.eventStart < 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttiming.events.push(performance.now() - timing.eventStart);\n\t\t\t\ttiming.eventStart = -1;\n\t\t\t},\n\t\t};\n\n\t\tthis.world.on(`system-${system.name}-worker-finished`, timing.onRunFinished);\n\t\tthis.world.on(`system-${system.name}-worker-events-finished`, timing.onEventsFinished);\n\t\tthis.systemTimings.set(system.name, timing);\n\t}\n\n\tprivate untrackSystem(name: string) {\n\t\tconst timing = this.systemTimings.get(name);\n\t\tif(!timing) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.world.off(`system-${name}-worker-finished`, timing.onRunFinished);\n\t\tthis.world.off(`system-${name}-worker-events-finished`, timing.onEventsFinished);\n\t\tthis.systemTimings.delete(name);\n\t}\n\n\tprivate recalculate() {\n\t\tconst systems = this.world.systems.map(system => {\n\t\t\tconst timing = this.systemTimings.get(system.name);\n\t\t\treturn {\n\t\t\t\tname: system.name,\n\t\t\t\trun: summarize(timing?.run ?? []),\n\t\t\t\tevents: summarize(timing?.events ?? []),\n\t\t\t};\n\t\t});\n\n\t\tconst events: TimingStats = { ...EMPTY_TIMING };\n\t\tsystems.forEach(system => {\n\t\t\tevents.avg += system.events.avg;\n\t\t\tevents.min += system.events.min;\n\t\t\tevents.max += system.events.max;\n\t\t\tevents.samples += system.events.samples;\n\t\t});\n\n\t\tthis.stats = {\n\t\t\tupdate: summarize(this.updateTimes),\n\t\t\tsystems,\n\t\t\tevents,\n\t\t};\n\n\t\tthis.ticks = 0;\n\t\tthis.updateTimes = [];\n\t\tthis.systemTimings.forEach(timing => {\n\t\t\ttiming.run = [];\n\t\t\ttiming.events = [];\n\t\t});\n\n\t\tthis.emit('stats-updated', this.stats);\n\t}\n}\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../node_modules/eventemitter3/index.js","../node_modules/eventemitter3/index.mjs","../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/entity-factory.ts","../src/world.ts","../src/actions/kill-entity.ts","../src/performance-timing.ts"],"sourcesContent":["'use strict';\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif ('undefined' !== typeof module) {\n module.exports = EventEmitter;\n}\n","import EventEmitter from './index.js'\n\nexport { EventEmitter }\nexport default EventEmitter\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { BaseComponent, ComponentDefinitionMap, ComponentMap, RegisteredComponentRegistry } from './component-definition';\nimport type { EntityComponent } from './entity-component';\n\nexport default class BaseEntity<C extends ComponentMap = ComponentMap, Cfg = any> extends EventEmitter {\n\treadonly eid: number;\n\tconfig?: Cfg;\n\n\tworld: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\t// entity is always present; game components are partial.\n\tcomponents: Partial<C> & { entity: EntityComponent } = {} as Partial<C> & { entity: EntityComponent };\n\n\t// `adoptEid`: build an empty shell around a pre-minted id (an entity a worker created off-thread), skipping the\n\t// automatic entity-component load - the caller (world.adoptEntity) loads the entity component and attaches the\n\t// worker-allocated blocks itself.\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C, Cfg>, config?: Cfg, adoptEid?: number) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.eid = adoptEid ?? world.allocateEid();\n\t\tif(adoptEid !== undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.loadComponent('entity', config ?? {}, false);\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, emitAdded = true): C[K] {\n\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\tconst memoryComponent = definition.memoryComponent;\n\t\tconst index = memoryComponent.create(definition.toBlock(config, this));\n\t\tconst component = definition.attach(this, memoryComponent, index);\n\t\t// A Component subclass already holds its block; only fetch one for a plain-object accessor that didn't.\n\t\t(component as BaseComponent).block ??= memoryComponent.getBlock(index);\n\t\t(this.components as Partial<C>)[name] = component;\n\t\tif(emitAdded) {\n\t\t\tthis.emit('component-added', name, component);\n\t\t}\n\n\t\treturn component;\n\t}\n\t// Builds an accessor over an existing block (allocated + written by a worker) instead of creating a new one - the\n\t// adopt half of loadComponent, without the create.\n\tattachComponent<K extends keyof C>(name: K, index: number): C[K] {\n\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\tconst component = definition.attach(this, definition.memoryComponent, index);\n\t\t(component as BaseComponent).block ??= definition.memoryComponent.getBlock(index);\n\t\t(this.components as Partial<C>)[name] = component;\n\t\treturn component;\n\t}\n\tremoveComponent<K extends keyof C>(name: K) {\n\t\tconst component = (this.components as Partial<C>)[name];\n\t\tif(component) {\n\t\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\t\tthis.world.deferComponentMemoryFree(definition.memoryComponent, component.index, definition.free ? () => definition.free!(component) : undefined);\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(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\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tconst components = this.components as Partial<C>;\n\t\tfor(let name of Object.keys(components) as Array<keyof C>) {\n\t\t\tconst definition = registry[name];\n\t\t\tconst component = components[name];\n\t\t\tif(component) {\n\t\t\t\tthis.world.deferComponentMemoryFree(definition.memoryComponent, component.index, definition.free ? () => definition.free!(component) : undefined);\n\t\t\t}\n\t\t}\n\t}\n\n\tload(config: Cfg) {\n\t\tconst props = config as Record<string, unknown>;\n\t\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tfor(let name of Object.keys(registry) as Array<keyof C>) {\n\t\t\tif(name === 'entity') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst definition = registry[name];\n\t\t\tif(definition.loadInFinishLoading) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(definition.loadProperties.some(prop => prop in props)) {\n\t\t\t\tthis.loadComponent(name, config, false);\n\t\t\t}\n\t\t}\n\n\t\tthis.config = config;\n\t}\n\tsave(): Cfg {\n\t\tconst config: { [key: string]: any } = {};\n\n\t\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tconst components = this.components as Partial<C>;\n\t\tfor(let name of Object.keys(components) as Array<keyof C>) {\n\t\t\tconst definition = registry[name];\n\t\t\tconst component = components[name];\n\t\t\tif(definition.save && component) {\n\t\t\t\tObject.assign(config, definition.save(component));\n\t\t\t}\n\t\t}\n\n\t\treturn config as Cfg;\n\t}\n\t// Second pass once every entity in a load batch exists; loads the deferred (loadInFinishLoading)\n\t// components load skipped. Overrides should call super.\n\tfinishLoading() {\n\t\tconst config = this.config;\n\t\tif(!config) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst props = config as Record<string, unknown>;\n\t\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\tfor(let name of Object.keys(registry) as Array<keyof C>) {\n\t\t\tif(name === 'entity') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst definition = registry[name];\n\t\t\tif(definition.loadInFinishLoading && definition.loadProperties.some(prop => prop in props)) {\n\t\t\t\tthis.loadComponent(name, config, false);\n\t\t\t}\n\t\t}\n\t}\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\n\n// Base system: runs on an optional fixed timestep (deltaBetweenRuns), driven by BaseWorld#update.\nexport default abstract class System<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\tworld: BaseWorld<ComponentDefinitionMap, C>;\n\tname: string;\n\tcurrentDelta: number = 0;\n\tdeltaBetweenRuns: number;\n\tfirstRun: boolean;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: SystemConfig = { name: 'System' }) {\n\t\tsuper();\n\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\t// Called once the world's entities all exist: the point a system hands its startup data off (see ComponentSystem).\n\tfinishLoading(): void | Promise<void> {}\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// Carry the remainder so a run that overshoots its timestep doesn't drift the next one later.\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\t\t\tthis.onRunFinished();\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\t// Logs and surfaces an error thrown by user code (an update body, preRun, etc.) on the main thread: a\n\t// `system-error` event carrying the system name, so a run keeps going past one failure instead of aborting.\n\tprotected onError(error: Error, context: { entityId?: number, phase?: SystemErrorPhase } = {}) {\n\t\tconst where = context.entityId !== undefined ? ` (entity ${context.entityId})` : '';\n\t\tconsole.error(`Error in system ${this.name}${where}: ${error.message}`, error);\n\t\tconst payload: SystemError = { system: this.name, error, entityId: context.entityId, phase: context.phase };\n\t\tthis.world.emit('system-error', payload);\n\t}\n\n\t// Marks one run as fully applied. Synchronous systems finish inside update(); subclasses whose work is\n\t// deferred (spread across frames, or off-thread) override this and call it at their real completion point.\n\tprotected onRunFinished() {\n\t\tthis.world.notifySystemRunCompleted(this);\n\t}\n\t// True while a run is still in progress between update() calls (a worker round-trip, or an iteration spread\n\t// across frames). Used by the world to keep waiting on a system that is mid-run over memory it may free.\n\tisCurrentlyRunning(): boolean {\n\t\treturn false;\n\t}\n\t// Resolves once any in-flight run has finished, so the world's clear() knows nothing is still reading memory\n\twaitForRunToComplete(): void | Promise<void> {}\n\n\tshouldRun(): boolean {\n\t\treturn true;\n\t}\n\n\tdestroy() {\n\t\tthis.removeAllListeners();\n\t}\n}\n\nexport interface SystemConfig {\n\tname: string\n\tdeltaBetweenRuns?: number\n\tfirstRun?: boolean\n}\n\n// Which part of a run threw, for the `system-error` event.\nexport type SystemErrorPhase = 'preRun' | 'update' | 'entityRemoved' | 'run';\nexport interface SystemError {\n\tsystem: string\n\terror: Error\n\tentityId?: number\n\tphase?: SystemErrorPhase\n}\n","import type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\nimport System, { type SystemConfig } from './system';\n\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<ComponentDefinitionMap, 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\t\t\tif(!this.remainingInstancesToRun.length) {\n\t\t\t\tthis.onRunFinished();\n\t\t\t}\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\t// A run that overflowed onto a later frame isn't finished yet; only count it once the queue drains (handled\n\t// by update() when it empties remainingInstancesToRun).\n\tprotected onRunFinished() {\n\t\tif(this.remainingInstancesToRun.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.onRunFinished();\n\t}\n\tisCurrentlyRunning(): boolean {\n\t\treturn this.remainingInstancesToRun.length > 0;\n\t}\n\n\trunIterables(iterables: Array<T>, elapsedTime: number) {\n\t\tlet started = performance.now();\n\t\ttry {\n\t\t\tthis.beforeRunIterables();\n\t\t} catch(e) {\n\t\t\t// preRun failed: skip the iteration this frame rather than run over half-prepared state.\n\t\t\tthis.onError(e as Error, { phase: 'preRun' });\n\t\t\tthis.remainingInstancesToRun = [];\n\t\t\tthis.remainingInstancesStartTime = null;\n\t\t\treturn;\n\t\t}\n\t\tfor(let i = 0; i < iterables.length; i++) {\n\t\t\ttry {\n\t\t\t\tthis.updateIterable(iterables[i], elapsedTime);\n\t\t\t} catch(e) {\n\t\t\t\t// One iterable failing must not stop the rest of the run.\n\t\t\t\tthis.onError(e as Error, { phase: 'update', entityId: this.getIterableEntityId(iterables[i]) });\n\t\t\t}\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\t// Best-effort eid for a failed iterable, so `system-error` can name it. Subclasses whose T carries an eid override.\n\tprotected getIterableEntityId(_iterable: T): number | undefined {\n\t\treturn undefined;\n\t}\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 { ComponentDefinitionMap, ComponentMap } from '../component-definition';\nimport IterableSystem, { type IterableSystemConfig } from './iterable-system';\n\n// Iterates the entities owning a given set of components on the main thread; membership tracks world events.\nexport default abstract class EntitySystem<C extends ComponentMap, T extends BaseEntity<C> = BaseEntity<C>> extends IterableSystem<C, T> {\n\tentities: Map<number, T> = new Map();\n\toptions: EntitySystemConfig<C>;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, 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\tconst iterables: Array<T> = [];\n\t\tthis.entities.forEach(entity => {\n\t\t\tif(!entity.components.entity.dead) {\n\t\t\t\titerables.push(entity);\n\t\t\t}\n\t\t});\n\n\t\treturn iterables;\n\t}\n\tupdateIterable(entity: T, elapsedTime: number): void {\n\t\tif(entity.components.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.components.entity.isStatic;\n\t}\n\tprotected getIterableEntityId(entity: T): number {\n\t\treturn entity.eid;\n\t}\n\tisEntityInSystem(entity: BaseEntity<C>) {\n\t\treturn this.entities.has(entity.eid);\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.set(entity.eid, 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\tthis.entities.delete(entity.eid);\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.size > 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 for the main-thread fallback. Loose params: this mirrors the DOM Worker boundary.\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 { applyQueryDelta } from './apply-query-delta';\nimport type ComponentWorkerMessage from './component-worker-message';\nimport type { EntityEvent, SystemEvents, WorkerRunError } from './component-worker-message';\nimport type BaseWorld from '../../world';\nimport type { ComponentDefinitionMap, ComponentMap, RegisteredComponentRegistry } from '../../component-definition';\nimport type {\n\tComponentSystemCallbacks, ComponentSystemWorld, EntityQueryComponents, EntityUpdateComponents,\n\tEntityUpdateFunction, QueryDelta, UpdateEntityConfigObject, WorkerAllocator, WorkerCreatedEntity,\n} from '../component-system';\nimport { buildWorkerEntity, type WorkerCreateRegistry } from '../../actions/build-worker-entity';\n\n// Main-thread fallback that runs the update function synchronously, mirroring the real worker's behavior.\nexport default class ComponentWebWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld, D = unknown> extends WebWorker {\n\tprivate updateFunction: EntityUpdateFunction<C, T, W, D>;\n\tprivate entities: Array<UpdateEntityConfigObject<T>> = [];\n\tprivate queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\t// Mirrors createComponentWorker: updateFunction.init's result, merged onto `world` each run.\n\tprivate worldExtension: Partial<W> | undefined;\n\t// Running on the main thread, this shares the world (its string cache, registry pools, eid counter) directly.\n\tprivate world: BaseWorld<ComponentDefinitionMap, C>;\n\tprivate allocator: WorkerAllocator;\n\tprivate createsEntities: boolean;\n\n\tconstructor(updateFunction: EntityUpdateFunction<C, T, W, D>, world: BaseWorld<ComponentDefinitionMap, C>, createsEntities = false) {\n\t\tsuper();\n\t\tthis.updateFunction = updateFunction;\n\t\tthis.world = world;\n\t\tthis.createsEntities = createsEntities;\n\t\tconst registry = world.registry as RegisteredComponentRegistry<C>;\n\t\tthis.allocator = {\n\t\t\tallocateEid: () => world.allocateEid(),\n\t\t\tallocateComponentBlock: (name, values) => registry[name as keyof C].memoryComponent.create(values),\n\t\t};\n\t}\n\n\tpostMessage(message: ComponentWorkerMessage<W, D>): void {\n\t\tif(message.type === 'init') {\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'init-complete',\n\t\t\t});\n\t\t} else if(message.type === 'load') {\n\t\t\tthis.worldExtension = this.updateFunction.init?.(message.data) ?? undefined;\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'reset') {\n\t\t\t// Drop the persistent lists so a reused world starts empty; worldExtension is refreshed by the next load.\n\t\t\tthis.entities = [];\n\t\t\tthis.queryEntities = {};\n\t\t} else if(message.type === 'run') {\n\t\t\tif(this.worldExtension) {\n\t\t\t\tObject.assign(message.world, this.worldExtension);\n\t\t\t}\n\t\t\tmessage.world.getString = (pointer: number) => this.world.constantStrings.getString(pointer) ?? '';\n\t\t\tmessage.world.heap = this.world.heap;\n\t\t\tmessage.world.allocate = this.allocator;\n\t\t\tif(this.createsEntities) {\n\t\t\t\tconst registry: WorkerCreateRegistry = this.world.registry;\n\t\t\t\tmessage.world.buildEntityDescriptor = config => buildWorkerEntity(config, this.world.factory.configs, registry, this.allocator);\n\t\t\t}\n\t\t\t// Timed like the real worker so a forceMainThread system reports a real run cost, not zero.\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<EntityEvent> = [];\n\t\t\tlet systemEvents: SystemEvents = {};\n\t\t\tlet createdEntities: Array<WorkerCreatedEntity> = [];\n\t\t\tlet errors: Array<WorkerRunError> = [];\n\n\t\t\tthis.entities = applyQueryDelta(this.entities, message.entities as QueryDelta<T>);\n\n\t\t\tlet queries: EntityQueryComponents<C> = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, delta]) => {\n\t\t\t\tconst list = applyQueryDelta(this.queryEntities[queryKey] ?? [], delta as QueryDelta<T>);\n\t\t\t\tthis.queryEntities[queryKey] = list;\n\t\t\t\tqueries[queryKey] = list;\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\temitEntityEvent(entityId: number, event: string, ...args: Array<unknown>) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\targs,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\temitSystemEvent(event: string, entityId: number) {\n\t\t\t\t\t(systemEvents[event] ?? (systemEvents[event] = [])).push(entityId);\n\t\t\t\t},\n\t\t\t\tentityDied(entityId: number) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'death',\n\t\t\t\t\t\targs: [],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tcreateEntity(entity: WorkerCreatedEntity) {\n\t\t\t\t\tcreatedEntities.push(entity);\n\t\t\t\t},\n\t\t\t};\n\t\t\tlet preRunFailed = false;\n\t\t\tif(this.updateFunction.preRun) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.updateFunction.preRun(message.world, this.entities, queries, callbacks);\n\t\t\t\t} catch(e) {\n\t\t\t\t\tpreRunFailed = true;\n\t\t\t\t\terrors.push({ error: e as Error, phase: 'preRun' });\n\t\t\t\t}\n\t\t\t}\n\t\t\t// preRun sets up the run's state; if it threw, skip the entity loop rather than run over half-prepared data.\n\t\t\tif(!preRunFailed) {\n\t\t\t\tthis.entities.forEach(entity => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.updateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t// One entity failing must not stop the rest of the run.\n\t\t\t\t\t\terrors.push({ error: e as Error, phase: 'update', entityId: entity.entityId });\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif(this.updateFunction.entityRemoved) {\n\t\t\t\tfor(let entityId of message.entities.removed) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.updateFunction.entityRemoved(message.world, entityId, callbacks);\n\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\terrors.push({ error: e as Error, phase: 'entityRemoved', entityId });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst runTime = performance.now() - start;\n\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\tgeneration: message.generation,\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tsystemEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t\terrors,\n\t\t\t});\n\t\t}\n\t}\n\n\tonMessageTyped(message: ComponentWorkerMessage<W, D>) {\n\t\tthis.onmessage({\n\t\t\tdata: message,\n\t\t});\n\t}\n}\n","import type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type { GrowBufferData } from '@daneren2005/shared-memory-objects/memory-heap';\nimport type BaseWorld from '../world';\nimport type BaseEntity from '../entity';\nimport type { BaseComponent, ComponentDefinitionMap, 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. Uses getWorker() when\n// Web Workers + SharedArrayBuffer exist, else falls back to ComponentWebWorker on the main thread. No game\n// concepts; games inject per-run data via addDataToWorld.\nexport default abstract class ComponentSystem<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n> extends System<C> {\n\tentities: Map<number, BaseEntity<C>> = new Map();\n\toptions: ComponentSystemConfig<C, T, W, D>;\n\n\tworker: Worker | ComponentWebWorker<C, T, W, D>;\n\tisWorkerThread: boolean;\n\n\tprivate initialized = false;\n\tprivate initPromise: Resolvable | null = null;\n\tprivate loadingPromise: Resolvable | null = null;\n\tprivate runCompletePromise: Resolvable | null = null;\n\tprivate isRunning = false;\n\t// Bumped by clear(); checked on each event to make certain we are dealing with the correct world\n\tprivate generation = 0;\n\tprivate queryEntities: { [key: string]: Map<number, BaseEntity<C>> } = {};\n\t// Membership changes since the last run(), flushed each run as a delta so a steady-state run sends empty\n\t// arrays rather than re-transmitting every eid. The worker applies these to its own list (see applyQueryDelta).\n\tprivate queryDeltas: { [key: string]: MembershipDelta<C> } = {};\n\n\taddDataToWorld?(world: W): void;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: ComponentSystemConfig<C, T, W, D>) {\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] = new Map();\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\t// Forward heap growth so the worker's reconstructed heap can resolve pointers into new buffers.\n\t\t\tworld.on('grow-buffer', (buffer: GrowBufferData) => {\n\t\t\t\tthis.worker.postMessage({ type: 'grow-buffer', buffer });\n\t\t\t});\n\t\t} else {\n\t\t\tthis.worker = new ComponentWebWorker(options.updateFunction, world, !!options.createsEntities);\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 === 'init-complete') {\n\t\t\t\tthis.initialized = true;\n\t\t\t\tif(this.initPromise) {\n\t\t\t\t\tthis.initPromise.resolve();\n\t\t\t\t\tthis.initPromise = null;\n\t\t\t\t}\n\t\t\t} else if(message.type === 'loaded') {\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 === 'grow-buffer-from-worker') {\n\t\t\t\t// A buffer this worker grew while allocating: adopt into the main heap and fan out to sibling workers.\n\t\t\t\tthis.world.addGrownBuffer(message.buffer);\n\t\t\t} else if(message.type === 'run-complete') {\n\t\t\t\t// A reply from a run that started before a clear(): the world it ran over is gone, so drop it whole.\n\t\t\t\tif(message.generation !== this.generation) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tthis.world.emit(`system-${this.name}-worker-finished`, message.runTime);\n\n\t\t\t\t// User-code errors caught inside the run: log + emit on the main thread, one per failure.\n\t\t\t\tmessage.errors.forEach(({ error, entityId, phase }) => {\n\t\t\t\t\tthis.onError(error, { entityId, phase });\n\t\t\t\t});\n\n\t\t\t\t// Before the per-entity events: an entity killed this run is still in the world here, since `death`\n\t\t\t\t// is dispatched below and removes it.\n\t\t\t\tfor(const event of Object.keys(message.systemEvents)) {\n\t\t\t\t\tthis.emit(event, message.systemEvents[event]);\n\t\t\t\t}\n\n\t\t\t\tmessage.events.forEach(event => {\n\t\t\t\t\t// Look up on the world, not the query cache, so events for sub-query-only entities still route.\n\t\t\t\t\tconst entity = this.world.getEntityByEid(event.entityId);\n\t\t\t\t\tif(!entity) {\n\t\t\t\t\t\tconsole.warn(`${this.name}-event ${event.event}: 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\n\t\t\t\t// After deaths, so an entity created this run isn't immediately removed. Adopts the blocks the worker\n\t\t\t\t// already allocated + wrote, rather than re-creating them.\n\t\t\t\tmessage.created.forEach(descriptor => {\n\t\t\t\t\tthis.world.adoptEntity(descriptor);\n\t\t\t\t});\n\n\t\t\t\tthis.world.emit(`system-${this.name}-worker-events-finished`, message.runTime);\n\t\t\t\tthis.world.notifySystemRunCompleted(this);\n\n\t\t\t\tif(this.runCompletePromise) {\n\t\t\t\t\tthis.runCompletePromise.resolve();\n\t\t\t\t\tthis.runCompletePromise = null;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage<W, D> = {\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.initialized) {\n\t\t\treturn;\n\t\t} else if(this.initPromise) {\n\t\t\treturn this.initPromise.promise;\n\t\t}\n\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\tthis.initPromise = {\n\t\t\tpromise,\n\t\t\tresolve,\n\t\t};\n\t\treturn promise;\n\t}\n\n\t// Sends the init data over and runs the update function's own init in the worker\n\tfinishLoading(): Promise<void> {\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\t// Assigned before posting: the main-thread fallback replies synchronously from inside postMessage.\n\t\tthis.loadingPromise = {\n\t\t\tpromise,\n\t\t\tresolve,\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage<W, D> = {\n\t\t\ttype: 'load',\n\t\t\tdata: this.options.getInitData?.(),\n\t\t\t// Only a real worker needs the buffers to rebuild a heap, plus the pools + eid counter to allocate off-thread.\n\t\t\theap: this.isWorkerThread ? this.world.heap.getSharedMemory() : undefined,\n\t\t\tsharedMemory: this.isWorkerThread ? this.world.getSharedComponentMemory() : undefined,\n\t\t\t// Factory templates only go to workers that create entities.\n\t\t\tfactoryConfigs: this.isWorkerThread && this.options.createsEntities ? this.world.factory.configs : undefined,\n\t\t};\n\t\tthis.worker.postMessage(message);\n\n\t\treturn promise;\n\t}\n\n\t// Un-initializes the system so its world can be reused\n\tclear() {\n\t\tsuper.clear();\n\n\t\tif(this.isRunning) {\n\t\t\tif(!this.runCompletePromise) {\n\t\t\t\tconst { promise, resolve } = Promise.withResolvers<void>();\n\t\t\t\tthis.runCompletePromise = { promise, resolve };\n\t\t\t}\n\t\t}\n\t\tthis.isRunning = false;\n\t\tthis.generation++;\n\n\t\tthis.entities.clear();\n\t\tObject.values(this.queryEntities).forEach(list => list.clear());\n\t\tthis.queryDeltas = {};\n\n\t\tconst message: ComponentWorkerMessage = { type: 'reset' };\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tupdate(elapsedTime: number): boolean {\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\t// A run finishes off-thread, not when update() returns; completedRuns is bumped on the worker's run-complete.\n\tprotected onRunFinished() {}\n\tisCurrentlyRunning(): boolean {\n\t\treturn this.isRunning;\n\t}\n\twaitForRunToComplete(): void | Promise<void> {\n\t\tif(!this.isRunning) {\n\t\t\treturn;\n\t\t}\n\t\tif(!this.runCompletePromise) {\n\t\t\tconst { promise, resolve } = Promise.withResolvers<void>();\n\t\t\tthis.runCompletePromise = { promise, resolve };\n\t\t}\n\t\treturn this.runCompletePromise.promise;\n\t}\n\trun(elapsedTime: number): void {\n\t\tconst world = {\n\t\t\tgameTime: this.world.gameTime,\n\t\t\telapsedTime,\n\t\t} as W;\n\t\tthis.addDataToWorld?.(world);\n\n\t\tthis.isRunning = true;\n\t\tlet entities = this.buildQueryDelta(MAIN_QUERY_NAME, this.options);\n\t\tlet queries: { [key: string]: QueryDelta<T> } = {};\n\t\tObject.entries(this.options.queries ?? {}).forEach(([queryKey, query]) => {\n\t\t\tqueries[queryKey] = this.buildQueryDelta(queryKey, query);\n\t\t});\n\t\tlet message: ComponentWorkerMessage<W> = {\n\t\t\ttype: 'run',\n\t\t\tgeneration: this.generation,\n\t\t\tworld,\n\t\t\tentities,\n\t\t\tqueries,\n\t\t};\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tprivate buildQueryDelta(queryName: string, query: ComponentSystemQuery<C>): QueryDelta<T> {\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tconst added: Array<UpdateEntityConfigObject<T>> = [];\n\t\tdelta.added.forEach(entity => {\n\t\t\tadded.push({\n\t\t\t\tentityId: entity.eid,\n\t\t\t\tcomponents: this.buildComponents(entity, query),\n\t\t\t});\n\t\t});\n\t\tconst removed = Array.from(delta.removed);\n\t\tthis.queryDeltas[queryName] = { added: new Set(), removed: new Set() };\n\n\t\treturn { added, removed };\n\t}\n\tprivate buildComponents(entity: BaseEntity<C>, query: ComponentSystemQuery<C>): T {\n\t\tconst components = {} as T;\n\t\t[\n\t\t\t...query.required,\n\t\t\t...query.optional ?? [],\n\t\t].forEach(componentName => {\n\t\t\t// Reuse the view cached on the accessor at attach: getBlock allocates a fresh subarray every call and an\n\t\t\t// entity joins many systems, so re-looking it up here per system was a measurable spawn-time cost.\n\t\t\tconst block = entity.components[componentName]?.block;\n\t\t\tif(block) {\n\t\t\t\tcomponents[componentName] = block as T[typeof componentName];\n\t\t\t}\n\t\t});\n\n\t\treturn components;\n\t}\n\n\tisEntityInSystem(entity: BaseEntity<C>) {\n\t\treturn this.entities.has(entity.eid);\n\t}\n\tprivate matchesQuery(entity: BaseEntity<C>, query: ComponentSystemQuery<C>): boolean {\n\t\tif(entity.components.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 getQueryDelta(queryName: string): MembershipDelta<C> {\n\t\tlet delta = this.queryDeltas[queryName];\n\t\tif(!delta) {\n\t\t\tdelta = this.queryDeltas[queryName] = { added: new Set(), removed: new Set() };\n\t\t}\n\n\t\treturn delta;\n\t}\n\t// A pending removal this same frame is cancelled, so the net effect is a re-send rather than remove+add churn.\n\tprivate markAdded(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tdelta.removed.delete(entity.eid);\n\t\tdelta.added.add(entity);\n\t}\n\tprivate markRemoved(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tif(delta.added.delete(entity)) {\n\t\t\treturn;\n\t\t}\n\n\t\tdelta.removed.add(entity.eid);\n\t}\n\tprivate updateEntityList(queryName: string, list: Map<number, BaseEntity<C>>, entity: BaseEntity<C>, shouldInclude: boolean) {\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tif(shouldInclude) {\n\t\t\tlist.set(entity.eid, entity);\n\t\t\tthis.markAdded(delta, entity);\n\t\t} else if(list.delete(entity.eid)) {\n\t\t\tthis.markRemoved(delta, entity);\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(MAIN_QUERY_NAME, 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] = new Map());\n\t\t\tthis.updateEntityList(queryName, queryList, entity, this.matchesQuery(entity, query));\n\t\t});\n\n\t\treturn shouldAddToMain;\n\t}\n\tremoveEntity(entity: BaseEntity<C>) {\n\t\tthis.updateEntityList(MAIN_QUERY_NAME, this.entities, entity, false);\n\t\tObject.entries(this.queryEntities).forEach(([queryName, list]) => {\n\t\t\tthis.updateEntityList(queryName, list, entity, false);\n\t\t});\n\t}\n\n\t// Re-evaluates every entity's membership against the current queries. Needed when a `filter` closes over mutable\n\t// state (e.g. a scope keyed on which group is active) and that state changes with no entity event to react to\n\trecheckMembership() {\n\t\tthis.world.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.size > 0;\n\t}\n\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tif('terminate' in this.worker) {\n\t\t\tthis.worker.terminate();\n\t\t}\n\t}\n}\n\ninterface Resolvable {\n\tpromise: Promise<void>\n\tresolve: (value: void | PromiseLike<void>) => void\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>, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentityId: number,\n\tcomponents: T,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\nexport type EntityUpdateFunction<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n> = EntityUpdateFunctionImpl<C, T, W> & {\n\tpreRun?: EntityUpdatePreRunFunction<C, T, W>\n\tentityRemoved?: EntityRemovedFunction<C, W>\n\tinit?: EntityUpdateInitFunction<W, D>\n};\nexport type EntityUpdateInitFunction<W extends ComponentSystemWorld = ComponentSystemWorld, D = unknown> = (data: D | undefined) => Partial<W> | void;\nexport type EntityUpdatePreRunFunction<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentities: Array<UpdateEntityConfigObject<T>>,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\nexport type EntityRemovedFunction<C extends ComponentMap = ComponentMap, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentityId: number,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => 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\nexport interface QueryDelta<T extends EntityUpdateComponents = EntityUpdateComponents> {\n\tadded: Array<UpdateEntityConfigObject<T>>\n\tremoved: Array<number>\n}\n// Sets so queuing can check for an already-queued or opposite change without scanning a growing array.\ninterface MembershipDelta<C extends ComponentMap> {\n\tadded: Set<BaseEntity<C>>\n\tremoved: Set<number>\n}\n\n// Low-level off-thread allocation primitives, injected onto the worker `world` each run. `allocateEid` mints a\n// heap-unique id; `allocateComponentBlock` pushes a block into a component's shared pool and returns its index.\n// These are the foundation a future worker-side createEntity builds on (allocate + write blocks, then report the\n// eid/indexes back for the main thread to adopt).\nexport interface WorkerAllocator {\n\tallocateEid(): number\n\tallocateComponentBlock(name: string, values: Array<number>): number\n}\n\nexport interface ComponentSystemWorld {\n\tgameTime: number\n\telapsedTime: number\n\tgetString(pointer: number): string\n\t// The reconstructed heap (real worker) or the shared main-thread heap (fallback), injected each run so an\n\t// update function can rebuild heap-backed structures (a SharedMap/SharedList) from a pointer in a component\n\t// block. Undefined only before the first run.\n\theap?: MemoryHeap\n\tallocate?: WorkerAllocator\n\t// Injected each run on a system registered with createsEntities: builds a WorkerCreatedEntity descriptor from a\n\t// factory config (merges the type's template, allocates + writes each component's block). Drives createEntityWorker.\n\tbuildEntityDescriptor?(config: WorkerCreateEntityConfig): WorkerCreatedEntity\n}\n// What a game passes to createEntityWorker: a factory-style config - the entity `type` plus any overrides layered\n// over that type's factory template. The worker merges template + overrides, then allocates + writes each triggered\n// component's block off-thread via the component's toBlock(config). The \"entity\" component is built on the main\n// thread when the descriptor is adopted, since interning the type is main-thread-only.\nexport type WorkerCreateEntityConfig = { type: string } & { [key: string]: unknown };\n// The result reported back on run-complete: the minted id plus, per game component, the pool index the worker\n// allocated. world.adoptEntity turns this into a real BaseEntity.\nexport interface WorkerCreatedEntity {\n\teid: number\n\ttype: string\n\tisStatic?: boolean\n\tcomponents: { [name: string]: number }\n}\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\t// Args are structured-cloned, so plain values only.\n\temitEntityEvent(entityId: number, event: string, ...args: Array<unknown>): void\n\t// Emitted **on the system** with all its ids in one array. The allocation-free path for something that\n\t// happens to most entities every run; carries no args (values are already in shared memory).\n\temitSystemEvent(event: string, entityId: number): void\n\tentityDied(entityId: number): void\n\tcreateEntity(entity: WorkerCreatedEntity): 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<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n\tD = unknown,\n> extends SystemConfig, ComponentSystemQuery<C> {\n\tupdateFunction: EntityUpdateFunction<C, T, W, D>\n\tgetWorker: () => Worker\n\tforceMainThread?: boolean\n\tgetInitData?: () => D\n\t// Opt in to worker-side entity creation (createEntityWorker). When set, the factory configs are shipped to this\n\t// system's worker on load so it can merge templates; the worker entry must also pass the component registry to\n\t// createComponentWorker so it has each component's toBlock(). Only systems that create entities need either.\n\tcreatesEntities?: boolean\n\n\tqueries?: { [key: string]: ComponentSystemQuery<C> }\n}\n\nexport type { BaseComponent };\n","import BaseEntity from './entity';\nimport type BaseWorld from './world';\nimport type { ComponentDefinitionMap, ComponentMap } from './component-definition';\n\n// Maps an entity `type` to a base (template) config; loading layers the caller's config over it.\nexport default class EntityFactory<C extends ComponentMap = ComponentMap, Cfg = any> {\n\tworld!: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\tconfigs: { [type: string]: Cfg };\n\n\tconstructor(configs: { [type: string]: Cfg } = {}) {\n\t\tthis.configs = configs;\n\t}\n\n\tregister(type: string, config: Cfg) {\n\t\tthis.configs[type] = config;\n\t}\n\n\tgetConfig(config: Cfg): Cfg {\n\t\tconst type = (config as { type?: string } | undefined)?.type;\n\t\tconst base = type ? this.configs[type] : undefined;\n\t\treturn base ? { ...base, ...config } : config;\n\t}\n\n\tloadEntity(config: Cfg, created = true): BaseEntity<C, Cfg> {\n\t\tconst entity = this.createEntity(this.getConfig(config));\n\t\treturn this.world.addEntity(entity, created);\n\t}\n\n\tprotected createEntity(config: Cfg): BaseEntity<C, Cfg> {\n\t\treturn new BaseEntity<C, Cfg>(this.world, config);\n\t}\n}\n","import { EventEmitter } from 'eventemitter3';\nimport MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';\nimport type { GrowBufferData } from '@daneren2005/shared-memory-objects/memory-heap';\nimport type AllocatedMemory from '@daneren2005/shared-memory-objects/allocated-memory';\nimport type { SharedAllocatedMemory } from '@daneren2005/shared-memory-objects/allocated-memory';\nimport type { SharedPoolMemory } from '@daneren2005/shared-memory-objects/shared-pool';\nimport { MAX_BYTE_OFFSET_LENGTH } from '@daneren2005/shared-memory-objects/utils/pointer';\nimport MemoryComponent from './memory-component';\nimport ConstantStringCache from './constant-string-cache';\nimport BaseEntity from './entity';\nimport type System from './systems/system';\nimport EntitySystem from './systems/entity-system';\nimport ComponentSystem from './systems/component-system';\nimport type { WorkerCreatedEntity } from './systems/component-system';\nimport type {\n\tBaseComponent, ComponentDefinitionMap, ComponentMap, ComponentRegistry, ComponentsOf,\n\tEntityConfigOf, RegisteredComponentDefinition, RegisteredComponentRegistry,\n} from './component-definition';\nimport { entityDefinition, type EntityComponent } from './entity-component';\nimport EntityFactory from './entity-factory';\n\nconst DEFAULT_HEAP_SIZE = MAX_BYTE_OFFSET_LENGTH;\nconst FREE_BUFFER_STUCK_MS = 10000;\n\ninterface DeferredComponentFree {\n\tmemoryComponent: MemoryComponent\n\tindex: number\n\t// The definition's free hook, deferred to fire alongside the block free rather than the instant the entity dies.\n\tfree?: () => void\n}\n// A batch of component blocks queued to be freed, plus the systems that must each finish a run before it is safe to free them\ninterface ComponentFreeBuffer<C extends ComponentMap> {\n\tfrees: Array<DeferredComponentFree>\n\twaitingSystems: Set<System<C>>\n\twaitElapsed: number\n}\n\nexport interface WorldOptions<C extends ComponentMap = ComponentMap, Cfg = any> {\n\theapSize?: number\n\tfactory?: EntityFactory<C, Cfg>\n}\n\nexport interface WorldConfig<Cfg = any> {\n\tentities: Array<Cfg>\n\tgameTime?: number\n\tplayerTime?: number\n\ttimeScale?: number\n}\n\n// Shipped to a worker so it can reconstruct handles over this world's shared state (see getSharedComponentMemory).\nexport interface WorldSharedMemory {\n\tcomponents: { [name: string]: SharedPoolMemory }\n\teidCounter: SharedAllocatedMemory\n}\n\nexport default class BaseWorld<\n\tR extends ComponentDefinitionMap = ComponentDefinitionMap,\n\tC extends ComponentMap = ComponentsOf<R>,\n\tCfg = EntityConfigOf<R>,\n> extends EventEmitter {\n\theap: MemoryHeap;\n\t// Interns entity type names (and any other constant strings) in the heap\n\tconstantStrings: ConstantStringCache;\n\t// Single heap-backed counter every thread bumps atomically, so eids stay unique whether an entity is created on\n\t// the main thread or inside a worker.\n\tprivate eidCounter: AllocatedMemory;\n\tregistry: RegisteredComponentRegistry<C> & { entity: RegisteredComponentDefinition<EntityComponent> };\n\tfactory: EntityFactory<C, Cfg>;\n\n\t// Keyed by eid: entities leave from the middle one at a time (every death), so a Map deletes in constant\n\t// time while still iterating in insertion order, preserving load/save order.\n\tentities: Map<number, BaseEntity<C, Cfg>> = new Map();\n\tsystems: Array<System<C>> = [];\n\n\tgameTime = 0;\n\t// Keeps advancing while paused and is never scaled by timeScale (unlike gameTime).\n\tplayerTime = 0;\n\ttimeScale = 1;\n\tpaused = false;\n\tdestroyed = false;\n\t// True while the world has never been loaded into\n\tpristine = true;\n\n\t// Two rolling buffers of component blocks awaiting a safe free. New deferrals land in `next`; `active` is the\n\t// one currently waiting for its systems to each finish a run before its blocks can be reused\n\tprivate activeFreeBuffer: ComponentFreeBuffer<C> = { frees: [], waitingSystems: new Set(), waitElapsed: 0 };\n\tprivate nextFreeBuffer: ComponentFreeBuffer<C> = { frees: [], waitingSystems: new Set(), waitElapsed: 0 };\n\n\t// The entity component is added automatically, so it must not be part of the passed registry.\n\tconstructor(registry: R, options: WorldOptions<C, Cfg> = {}) {\n\t\tsuper();\n\n\t\tthis.heap = new MemoryHeap({ bufferSize: options.heapSize ?? DEFAULT_HEAP_SIZE });\n\t\tthis.constantStrings = new ConstantStringCache(this.heap);\n\t\tthis.eidCounter = this.heap.allocUI32(1);\n\t\t// A grown buffer must reach every worker's reconstructed heap so pointers into it still resolve.\n\t\tthis.heap.addOnGrowBufferHandlers((data: GrowBufferData) => this.emit('grow-buffer', data));\n\n\t\tconst inputRegistry = { ...registry, entity: entityDefinition } as ComponentRegistry<C> & { entity: typeof entityDefinition };\n\t\tconst registry_: Record<string, RegisteredComponentDefinition<BaseComponent>> = {};\n\t\tfor(let name of Object.keys(inputRegistry)) {\n\t\t\tconst definition = inputRegistry[name as keyof typeof inputRegistry];\n\t\t\tregistry_[name] = {\n\t\t\t\t...definition,\n\t\t\t\tmemoryComponent: new MemoryComponent(this.heap, definition.type, definition.size),\n\t\t\t};\n\t\t}\n\t\tthis.registry = registry_ as RegisteredComponentRegistry<C> & { entity: RegisteredComponentDefinition<EntityComponent> };\n\n\t\tthis.factory = options.factory ?? new EntityFactory<C, Cfg>();\n\t\tthis.factory.world = this;\n\t}\n\n\t// Returns a fresh, unique entity id. Backed by a heap atomic so a worker allocating an entity gets an id that can\n\t// never collide with one the main thread (or another worker) hands out. First id is 1, matching the old counter.\n\tallocateEid(): number {\n\t\treturn Atomics.add(this.eidCounter.data, 0, 1) + 1;\n\t}\n\t// Everything a worker needs to reconstruct handles over this world's shared state: one SharedPoolMemory per\n\t// registered component (so it can allocate/read blocks) plus the eid counter (so it can mint unique ids).\n\tgetSharedComponentMemory(): WorldSharedMemory {\n\t\tconst components: { [name: string]: SharedPoolMemory } = {};\n\t\tfor(let name of Object.keys(this.registry)) {\n\t\t\tcomponents[name] = this.registry[name as keyof typeof this.registry].memoryComponent.getSharedMemory();\n\t\t}\n\t\treturn {\n\t\t\tcomponents,\n\t\t\teidCounter: this.eidCounter.getSharedMemory(),\n\t\t};\n\t}\n\t// A buffer that was grown inside a worker: adopt it into the main heap (if not already present) and fan it out to\n\t// every other worker so their heaps can resolve pointers into it. The heap's BUFFER_COUNT is authoritative, so\n\t// re-adding an already-known position is a harmless overwrite of the same SharedArrayBuffer.\n\taddGrownBuffer(data: GrowBufferData) {\n\t\tif(this.heap.buffers[data.bufferPosition] === undefined) {\n\t\t\tthis.heap.addSharedBuffer(data);\n\t\t}\n\t\tthis.emit('grow-buffer', data);\n\t}\n\n\t// Only an off-thread ComponentSystem that creates entities allocates in a worker, so only then is a pre-fanned-out\n\t// spare buffer worth keeping (growing one otherwise just wastes a whole buffer). The main-thread fallback allocates\n\t// on the main thread, where growth fans out inline, so it never needs one.\n\tprivate get needsSpareBuffer(): boolean {\n\t\treturn this.systems.some(system => system instanceof ComponentSystem && system.isWorkerThread && !!system.options.createsEntities);\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\tprivate finishLoadingSystems() {\n\t\treturn Promise.all(this.systems.map(system => system.finishLoading()).filter(promise => promise instanceof Promise));\n\t}\n\n\taddEntity(entity: BaseEntity<C, Cfg>, created = true): BaseEntity<C, Cfg> {\n\t\tthis.entities.set(entity.eid, entity);\n\t\tentity.world = this;\n\t\t// Any entity in the world means there is state to tear down on the next load/clear.\n\t\tthis.pristine = false;\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\tthis.emit('entity-added', entity);\n\t\t\tentity.on('death', () => {\n\t\t\t\tthis.onEntityDied(entity);\n\t\t\t});\n\t\t}\n\n\t\treturn entity;\n\t}\n\tloadEntity(config: Cfg, created = true): BaseEntity<C, Cfg> {\n\t\treturn this.factory.loadEntity(config, created);\n\t}\n\t// Materializes an entity a worker created off-thread (see createEntityWorker): the worker already minted the id and\n\t// allocated + wrote every game-component block, so this only builds the `entity` component on the main thread\n\t// (interning its type) and adopts each worker-allocated block by index, then wires it into the world like any new\n\t// entity. Adopted entities are always the base BaseEntity - the factory's per-type subclass/template is not applied.\n\tadoptEntity(descriptor: WorkerCreatedEntity): BaseEntity<C, Cfg> {\n\t\tconst entity = new BaseEntity<C, Cfg>(this, undefined, descriptor.eid);\n\t\tentity.loadComponent('entity', { type: descriptor.type, isStatic: descriptor.isStatic }, false);\n\t\tfor(let name of Object.keys(descriptor.components)) {\n\t\t\tentity.attachComponent(name, descriptor.components[name]);\n\t\t}\n\t\treturn this.addEntity(entity, true);\n\t}\n\t// Replaces the world's contents. Entities load with created = false so no finishLoading runs mid-batch;\n\t// finishLoading is called on each once the whole batch exists, so cross-entity dependencies can resolve.\n\tload(config: WorldConfig<Cfg>) {\n\t\t// A pristine world (fresh or just cleared) has nothing to tear down, so skip the per-system clear.\n\t\tif(!this.pristine) {\n\t\t\t// Iterate over a copy since removeEntity mutates `this.entities`.\n\t\t\tfor(let entity of Array.from(this.entities.values())) {\n\t\t\t\tthis.removeEntity(entity);\n\t\t\t}\n\t\t\tthis.systems.forEach(system => system.clear());\n\t\t\tthis.consolidateFreeBuffersForReload();\n\t\t}\n\n\t\t// Intern a constant string for every type the factory knows, so a worker can resolve any type - even one no\n\t\t// currently-loaded entity uses. Deduped, so the types actually loaded below cost nothing extra.\n\t\tfor(let type of Object.keys(this.factory.configs)) {\n\t\t\tthis.constantStrings.getOrCreate(type);\n\t\t}\n\n\t\tconst entities = config.entities.map(entityConfig => this.loadEntity(entityConfig, false));\n\t\tfor(let entity of entities) {\n\t\t\tentity.finishLoading();\n\t\t\tthis.emit('entity-added', entity);\n\t\t\tentity.on('death', () => {\n\t\t\t\tthis.onEntityDied(entity);\n\t\t\t});\n\t\t}\n\n\t\tthis.gameTime = config.gameTime ?? 0;\n\t\tthis.playerTime = config.playerTime ?? 0;\n\t\tthis.timeScale = config.timeScale ?? 1;\n\n\t\t// ComponentSystem re-sends its init data here.\n\t\tvoid this.finishLoadingSystems();\n\t}\n\tasync clear(): Promise<void> {\n\t\tif(this.pristine) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor(let entity of Array.from(this.entities.values())) {\n\t\t\tthis.removeEntity(entity);\n\t\t}\n\t\tthis.systems.forEach(system => system.clear());\n\t\tawait Promise.all(\n\t\t\tthis.systems\n\t\t\t\t.map(system => system.waitForRunToComplete())\n\t\t\t\t.filter(promise => promise instanceof Promise),\n\t\t);\n\t\tthis.freeAllPendingBuffers();\n\n\t\tthis.pristine = true;\n\t}\n\tremoveEntity(entity: BaseEntity<C, Cfg>) {\n\t\t// delete reports whether it was actually present, so a double-remove emits entity-removed only once.\n\t\tif(this.entities.delete(entity.eid)) {\n\t\t\tthis.emit('entity-removed', entity);\n\t\t}\n\n\t\tentity.deleteAllComponentMemory();\n\t}\n\tonEntityDied(entity: BaseEntity<C, Cfg>) {\n\t\tthis.removeEntity(entity);\n\t}\n\tgetEntityByEid(eid: number): BaseEntity<C, Cfg> | undefined {\n\t\treturn this.entities.get(eid);\n\t}\n\n\t// Queues a component block to be freed when all systems done using it, running the definition's free hook (if any)\n\t// at that same deferred point so a system still mid-run can't observe the resource being torn down early.\n\tdeferComponentMemoryFree(memoryComponent: MemoryComponent, index: number, free?: () => void) {\n\t\tthis.nextFreeBuffer.frees.push({ memoryComponent, index, free });\n\t}\n\t// A system finished a run; if the active buffer was waiting on it, drop it and, once nothing is left to wait\n\t// for, free the buffer. One completion is enough: the system is now done touching the block for that run, and\n\t// every later run applies the pending removed-delta before its update loop, so it can never process the freed\n\t// entity again.\n\tnotifySystemRunCompleted(system: System<C>) {\n\t\tif(this.activeFreeBuffer.waitingSystems.delete(system) && this.activeFreeBuffer.waitingSystems.size === 0) {\n\t\t\tthis.processFreeBuffers();\n\t\t}\n\t}\n\tprivate processFreeBuffers() {\n\t\t// Loop so a promoted buffer with no systems to wait for is freed the same tick rather than a frame later.\n\t\twhile(this.activeFreeBuffer.waitingSystems.size === 0) {\n\t\t\tif(this.activeFreeBuffer.frees.length > 0) {\n\t\t\t\tthis.performFrees(this.activeFreeBuffer);\n\t\t\t}\n\t\t\tif(this.nextFreeBuffer.frees.length === 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.promoteNextFreeBuffer();\n\t\t}\n\t}\n\tprivate promoteNextFreeBuffer() {\n\t\t// active is now empty (its frees were performed); swap roles and reuse it as the new next buffer.\n\t\tconst emptied = this.activeFreeBuffer;\n\t\tthis.activeFreeBuffer = this.nextFreeBuffer;\n\t\tthis.nextFreeBuffer = emptied;\n\n\t\tconst active = this.activeFreeBuffer;\n\t\tactive.waitElapsed = 0;\n\t\tactive.waitingSystems.clear();\n\t\tfor(let system of this.systems) {\n\t\t\t// Wait on a system if it will run (and so might pick up this block) or is already mid-run over memory we\n\t\t\t// may free. A system that is neither can't touch these blocks, so there's nothing to wait for.\n\t\t\tif(system.shouldRun() || system.isCurrentlyRunning()) {\n\t\t\t\tactive.waitingSystems.add(system);\n\t\t\t}\n\t\t}\n\t}\n\t// On reload every system was just cleared (its completedRuns reset and worker told to drop its lists), so the\n\t// old targets no longer apply. Collapse whatever was pending into `next` with a fresh (empty) active buffer\n\tprivate consolidateFreeBuffersForReload() {\n\t\tif(this.activeFreeBuffer.frees.length > 0) {\n\t\t\tthis.nextFreeBuffer.frees.push(...this.activeFreeBuffer.frees);\n\t\t\tthis.activeFreeBuffer.frees.length = 0;\n\t\t}\n\t\tthis.activeFreeBuffer.waitingSystems.clear();\n\t\tthis.activeFreeBuffer.waitElapsed = 0;\n\t}\n\t// Frees both buffers outright. Only safe once every system's in-flight run has finished (see clear()), since it\n\t// skips the per-system wait the update loop normally enforces.\n\tprivate freeAllPendingBuffers() {\n\t\tthis.performFrees(this.activeFreeBuffer);\n\t\tthis.performFrees(this.nextFreeBuffer);\n\t\tthis.activeFreeBuffer.waitingSystems.clear();\n\t\tthis.activeFreeBuffer.waitElapsed = 0;\n\t\tthis.nextFreeBuffer.waitingSystems.clear();\n\t\tthis.nextFreeBuffer.waitElapsed = 0;\n\t}\n\tprivate performFrees(buffer: ComponentFreeBuffer<C>) {\n\t\tfor(let deferred of buffer.frees) {\n\t\t\tdeferred.free?.();\n\t\t\tdeferred.memoryComponent.delete(deferred.index);\n\t\t}\n\t\tbuffer.frees.length = 0;\n\t}\n\tprivate checkFreeBufferTimeout(elapsedTime: number) {\n\t\tconst active = this.activeFreeBuffer;\n\t\tif(active.waitingSystems.size === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tactive.waitElapsed += elapsedTime;\n\t\tif(active.waitElapsed >= FREE_BUFFER_STUCK_MS) {\n\t\t\tconst stuck = Array.from(active.waitingSystems).map(system => system.name).join(', ');\n\t\t\tconsole.warn(`shared-memory-ecs: deferred component free waited over ${FREE_BUFFER_STUCK_MS}ms on system(s): ${stuck}; freeing anyway`);\n\t\t\tactive.waitingSystems.clear();\n\t\t\tthis.processFreeBuffers();\n\t\t}\n\t}\n\n\taddSystem<T extends System<C>>(system: T): T {\n\t\tthis.systems.push(system);\n\t\tthis.emit('system-added', 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\tthis.emit('system-added', 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\tconst [system] = this.systems.splice(index, 1);\n\t\t\tthis.emit('system-removed', system);\n\t\t}\n\t}\n\n\tupdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\tthis.emit('update-started', elapsedTime);\n\t\tconst result = this.runUpdate(elapsedTime);\n\t\tthis.emit('update-finished', elapsedTime);\n\n\t\treturn result;\n\t}\n\tprivate runUpdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\tthis.playerTime += elapsedTime;\n\t\tif(this.paused) {\n\t\t\treturn {};\n\t\t}\n\t\tconst unscaledElapsedTime = elapsedTime;\n\t\telapsedTime = this.timeScale * elapsedTime;\n\n\t\tthis.gameTime += elapsedTime;\n\n\t\t// Promote before running: a run this same update then counts toward the wait, instead of after it.\n\t\tthis.processFreeBuffers();\n\n\t\t// Keep an empty heap buffer fanned out ahead of any worker that allocates off-thread, so its allocations land in\n\t\t// a buffer every thread already holds. Done here (before dispatching runs) so the resulting grow-buffer message\n\t\t// is queued to each worker before its run message - postMessage is FIFO, so the worker has the buffer first.\n\t\tif(this.needsSpareBuffer) {\n\t\t\tthis.heap.ensureSpareBuffer();\n\t\t}\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\tthis.emit('system-error', { system: system.name, error, phase: 'run' });\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\tthis.checkFreeBufferTimeout(unscaledElapsedTime);\n\n\t\treturn {\n\t\t\tlastSystemError,\n\t\t};\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t}\n\tresume() {\n\t\tthis.paused = false;\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, any>, 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 BaseEntity from '../entity';\n\n// Flags the entity dead in shared memory and emits `death`; BaseWorld listens for it to remove the entity.\nexport default function killEntity(entity: BaseEntity): void {\n\tentity.components.entity.dead = true;\n\tentity.emit('death');\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { ComponentDefinitionMap, ComponentMap } from './component-definition';\nimport type System from './systems/system';\n\nexport const DEFAULT_TICKS_BETWEEN_UPDATES = 1_000;\n\nexport interface TimingStats {\n\tavg: number\n\tmin: number\n\tmax: number\n\tsamples: number\n}\n\nexport interface SystemTimingStats {\n\tname: string\n\trun: TimingStats\n\tevents: TimingStats\n}\n\nexport interface PerformanceStats {\n\tupdate: TimingStats\n\tsystems: Array<SystemTimingStats>\n\tevents: TimingStats\n}\n\nexport interface PerformanceTimingOptions {\n\tticksBetweenUpdates?: number\n}\n\ninterface SystemTiming {\n\trun: Array<number>\n\tevents: Array<number>\n\t// -1 when no run is being dispatched.\n\teventStart: number\n\tonRunFinished: (runTime: number) => void\n\tonEventsFinished: () => void\n}\n\nconst EMPTY_TIMING: TimingStats = { avg: 0, min: 0, max: 0, samples: 0 };\n\n// An empty window reads as zeroes (not an infinite min) so a snapshot is always safe to render.\nfunction summarize(samples: Array<number>): TimingStats {\n\tif(!samples.length) {\n\t\treturn { ...EMPTY_TIMING };\n\t}\n\n\tlet total = 0;\n\tlet min = Infinity;\n\tlet max = 0;\n\tfor(let sample of samples) {\n\t\ttotal += sample;\n\t\tif(sample < min) {\n\t\t\tmin = sample;\n\t\t}\n\t\tif(sample > max) {\n\t\t\tmax = sample;\n\t\t}\n\t}\n\n\treturn {\n\t\tavg: total / samples.length,\n\t\tmin,\n\t\tmax,\n\t\tsamples: samples.length,\n\t};\n}\n\n// Watches a world and reports what it costs to run, driven off events the world emits. Emits `stats-updated`\n// every `ticksBetweenUpdates`; paused frames are skipped.\nexport default class PerformanceTiming<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\tworld: BaseWorld<ComponentDefinitionMap, C>;\n\tticksBetweenUpdates: number;\n\tstats: PerformanceStats = {\n\t\tupdate: { ...EMPTY_TIMING },\n\t\tsystems: [],\n\t\tevents: { ...EMPTY_TIMING },\n\t};\n\n\tprivate ticks = 0;\n\tprivate updateStart = 0;\n\tprivate updateTimes: Array<number> = [];\n\tprivate systemTimings = new Map<string, SystemTiming>();\n\tprivate destroyed = false;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: PerformanceTimingOptions = {}) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.ticksBetweenUpdates = options.ticksBetweenUpdates ?? DEFAULT_TICKS_BETWEEN_UPDATES;\n\n\t\tworld.on('update-started', this.onUpdateStarted);\n\t\tworld.on('update-finished', this.onUpdateFinished);\n\t\tworld.on('system-added', this.onSystemAdded);\n\t\tworld.on('system-removed', this.onSystemRemoved);\n\t\tworld.systems.forEach(system => this.trackSystem(system));\n\t}\n\n\tgetSystemStats(name: string): SystemTimingStats | undefined {\n\t\treturn this.stats.systems.find(system => system.name === name);\n\t}\n\n\treset() {\n\t\tthis.ticks = 0;\n\t\tthis.updateTimes = [];\n\t\tthis.systemTimings.forEach(timing => {\n\t\t\ttiming.run = [];\n\t\t\ttiming.events = [];\n\t\t\ttiming.eventStart = -1;\n\t\t});\n\t\tthis.stats = {\n\t\t\tupdate: { ...EMPTY_TIMING },\n\t\t\tsystems: [],\n\t\t\tevents: { ...EMPTY_TIMING },\n\t\t};\n\t}\n\n\tdestroy() {\n\t\tif(this.destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.destroyed = true;\n\n\t\tthis.world.off('update-started', this.onUpdateStarted);\n\t\tthis.world.off('update-finished', this.onUpdateFinished);\n\t\tthis.world.off('system-added', this.onSystemAdded);\n\t\tthis.world.off('system-removed', this.onSystemRemoved);\n\t\tArray.from(this.systemTimings.keys()).forEach(name => this.untrackSystem(name));\n\t\tthis.removeAllListeners();\n\t}\n\n\tprivate onUpdateStarted = () => {\n\t\tthis.updateStart = performance.now();\n\t};\n\n\tprivate onUpdateFinished = (elapsedTime: number) => {\n\t\tif(this.world.paused) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateTimes.push(performance.now() - this.updateStart);\n\n\t\tthis.ticks += elapsedTime;\n\t\tif(this.ticks >= this.ticksBetweenUpdates) {\n\t\t\tthis.recalculate();\n\t\t}\n\t};\n\n\tprivate onSystemAdded = (system: System<C>) => {\n\t\tthis.trackSystem(system);\n\t};\n\n\tprivate onSystemRemoved = (system: System<C>) => {\n\t\tthis.untrackSystem(system.name);\n\t};\n\n\t// The gap between `-worker-finished` (before events dispatch) and `-worker-events-finished` (after) is what\n\t// that run cost this thread. Both fire for the main-thread fallback too.\n\tprivate trackSystem(system: System<C>) {\n\t\tif(this.systemTimings.has(system.name)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst timing: SystemTiming = {\n\t\t\trun: [],\n\t\t\tevents: [],\n\t\t\teventStart: -1,\n\t\t\tonRunFinished: (runTime: number) => {\n\t\t\t\ttiming.run.push(runTime);\n\t\t\t\ttiming.eventStart = performance.now();\n\t\t\t},\n\t\t\tonEventsFinished: () => {\n\t\t\t\tif(timing.eventStart < 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttiming.events.push(performance.now() - timing.eventStart);\n\t\t\t\ttiming.eventStart = -1;\n\t\t\t},\n\t\t};\n\n\t\tthis.world.on(`system-${system.name}-worker-finished`, timing.onRunFinished);\n\t\tthis.world.on(`system-${system.name}-worker-events-finished`, timing.onEventsFinished);\n\t\tthis.systemTimings.set(system.name, timing);\n\t}\n\n\tprivate untrackSystem(name: string) {\n\t\tconst timing = this.systemTimings.get(name);\n\t\tif(!timing) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.world.off(`system-${name}-worker-finished`, timing.onRunFinished);\n\t\tthis.world.off(`system-${name}-worker-events-finished`, timing.onEventsFinished);\n\t\tthis.systemTimings.delete(name);\n\t}\n\n\tprivate recalculate() {\n\t\tconst systems = this.world.systems.map(system => {\n\t\t\tconst timing = this.systemTimings.get(system.name);\n\t\t\treturn {\n\t\t\t\tname: system.name,\n\t\t\t\trun: summarize(timing?.run ?? []),\n\t\t\t\tevents: summarize(timing?.events ?? []),\n\t\t\t};\n\t\t});\n\n\t\tconst events: TimingStats = { ...EMPTY_TIMING };\n\t\tsystems.forEach(system => {\n\t\t\tevents.avg += system.events.avg;\n\t\t\tevents.min += system.events.min;\n\t\t\tevents.max += system.events.max;\n\t\t\tevents.samples += system.events.samples;\n\t\t});\n\n\t\tthis.stats = {\n\t\t\tupdate: summarize(this.updateTimes),\n\t\t\tsystems,\n\t\t\tevents,\n\t\t};\n\n\t\tthis.ticks = 0;\n\t\tthis.updateTimes = [];\n\t\tthis.systemTimings.forEach(timing => {\n\t\t\ttiming.run = [];\n\t\t\ttiming.events = [];\n\t\t});\n\n\t\tthis.emit('stats-updated', this.stats);\n\t}\n}\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';
|
|
1
2
|
import type BaseWorld from '../world';
|
|
2
3
|
import type BaseEntity from '../entity';
|
|
3
4
|
import type { BaseComponent, ComponentDefinitionMap, ComponentMap } from '../component-definition';
|
|
@@ -77,6 +78,7 @@ export interface ComponentSystemWorld {
|
|
|
77
78
|
gameTime: number;
|
|
78
79
|
elapsedTime: number;
|
|
79
80
|
getString(pointer: number): string;
|
|
81
|
+
heap?: MemoryHeap;
|
|
80
82
|
allocate?: WorkerAllocator;
|
|
81
83
|
buildEntityDescriptor?(config: WorkerCreateEntityConfig): WorkerCreatedEntity;
|
|
82
84
|
}
|
|
@@ -9,6 +9,7 @@ export default abstract class EntitySystem<C extends ComponentMap, T extends Bas
|
|
|
9
9
|
getIterables(): Array<T>;
|
|
10
10
|
updateIterable(entity: T, elapsedTime: number): void;
|
|
11
11
|
filterEntity(entity: BaseEntity<C>): boolean;
|
|
12
|
+
protected getIterableEntityId(entity: T): number;
|
|
12
13
|
isEntityInSystem(entity: BaseEntity<C>): boolean;
|
|
13
14
|
abstract updateEntity(entity: T, elapsedTime: number): void;
|
|
14
15
|
checkAddEntity(entity: BaseEntity<C>): boolean;
|
|
@@ -14,6 +14,7 @@ export default abstract class IterableSystem<C extends ComponentMap, T> extends
|
|
|
14
14
|
isCurrentlyRunning(): boolean;
|
|
15
15
|
runIterables(iterables: Array<T>, elapsedTime: number): void;
|
|
16
16
|
beforeRunIterables(): void;
|
|
17
|
+
protected getIterableEntityId(_iterable: T): number | undefined;
|
|
17
18
|
abstract getIterables(): Array<T>;
|
|
18
19
|
abstract updateIterable(iterable: T, elapsedTime: number): void;
|
|
19
20
|
}
|
package/dist/systems/system.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export default abstract class System<C extends ComponentMap = ComponentMap> exte
|
|
|
13
13
|
finishLoading(): void | Promise<void>;
|
|
14
14
|
update(elapsedTime: number): boolean;
|
|
15
15
|
abstract run(elapsedTime: number): void;
|
|
16
|
+
protected onError(error: Error, context?: {
|
|
17
|
+
entityId?: number;
|
|
18
|
+
phase?: SystemErrorPhase;
|
|
19
|
+
}): void;
|
|
16
20
|
protected onRunFinished(): void;
|
|
17
21
|
isCurrentlyRunning(): boolean;
|
|
18
22
|
waitForRunToComplete(): void | Promise<void>;
|
|
@@ -24,3 +28,10 @@ export interface SystemConfig {
|
|
|
24
28
|
deltaBetweenRuns?: number;
|
|
25
29
|
firstRun?: boolean;
|
|
26
30
|
}
|
|
31
|
+
export type SystemErrorPhase = 'preRun' | 'update' | 'entityRemoved' | 'run';
|
|
32
|
+
export interface SystemError {
|
|
33
|
+
system: string;
|
|
34
|
+
error: Error;
|
|
35
|
+
entityId?: number;
|
|
36
|
+
phase?: SystemErrorPhase;
|
|
37
|
+
}
|
|
@@ -44,6 +44,11 @@ export interface EntityEvent {
|
|
|
44
44
|
event: string;
|
|
45
45
|
args: Array<unknown>;
|
|
46
46
|
}
|
|
47
|
+
export interface WorkerRunError {
|
|
48
|
+
error: Error;
|
|
49
|
+
phase: 'preRun' | 'update' | 'entityRemoved';
|
|
50
|
+
entityId?: number;
|
|
51
|
+
}
|
|
47
52
|
export type SystemEvents = {
|
|
48
53
|
[event: string]: Array<number>;
|
|
49
54
|
};
|
|
@@ -54,6 +59,7 @@ interface EntityEventsMessage {
|
|
|
54
59
|
events: Array<EntityEvent>;
|
|
55
60
|
systemEvents: SystemEvents;
|
|
56
61
|
created: Array<WorkerCreatedEntity>;
|
|
62
|
+
errors: Array<WorkerRunError>;
|
|
57
63
|
}
|
|
58
64
|
type ComponentWorkerMessage<W extends ComponentSystemWorld = ComponentSystemWorld, D = unknown> = InitMessage | InitCompleteMessage | LoadMessage<D> | LoadedMessage | ResetMessage | GrowBufferMessage | GrowBufferFromWorkerMessage | RunUpdateMessage<W> | EntityEventsMessage;
|
|
59
65
|
export default ComponentWorkerMessage;
|
package/dist/worker.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as e, n as t, o as n, r, t as i } from "./create-component-worker-
|
|
1
|
+
import { i as e, n as t, o as n, r, t as i } from "./create-component-worker-BM942gjg.js";
|
|
2
2
|
export { e as DEAD_INDEX, n as TYPE_INDEX, i as createComponentWorker, t as createEntityWorker, r as killEntityWorker };
|
package/dist/world.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export default class BaseWorld<R extends ComponentDefinitionMap = ComponentDefin
|
|
|
49
49
|
allocateEid(): number;
|
|
50
50
|
getSharedComponentMemory(): WorldSharedMemory;
|
|
51
51
|
addGrownBuffer(data: GrowBufferData): void;
|
|
52
|
+
private get needsSpareBuffer();
|
|
52
53
|
init(): Promise<void>;
|
|
53
54
|
private finishLoadingSystems;
|
|
54
55
|
addEntity(entity: BaseEntity<C, Cfg>, created?: boolean): BaseEntity<C, Cfg>;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@daneren2005/shared-memory-ecs",
|
|
3
3
|
"description": "A small, reusable Entity/Component/System core backed by shared memory.",
|
|
4
4
|
"author": "Scott Jackson",
|
|
5
|
-
"version": "1.5.
|
|
5
|
+
"version": "1.5.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
|
8
8
|
"repository": {
|
|
@@ -61,6 +61,6 @@
|
|
|
61
61
|
"vitest": "^4.1.10"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@daneren2005/shared-memory-objects": "^1.
|
|
64
|
+
"@daneren2005/shared-memory-objects": "^1.3.0"
|
|
65
65
|
}
|
|
66
66
|
}
|