@daneren2005/shared-memory-ecs 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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/memory-component.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.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 LocalPool from '@daneren2005/shared-memory-objects/local-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\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: LocalPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number) {\n\t\tthis.heap = heap;\n\t\tthis.pool = new LocalPool(heap, {\n\t\t\ttype,\n\t\t\tdataLength,\n\t\t});\n\t}\n\n\tget length() {\n\t\treturn this.pool.length;\n\t}\n\tget rawLength() {\n\t\treturn this.pool.bufferLength;\n\t}\n\n\tcreate(values: Array<number>): number {\n\t\treturn this.pool.push(values);\n\t}\n\n\tgetBlock(index: number): T {\n\t\treturn this.pool.at(index);\n\t}\n\tget(index: number, dataIndex: number): number {\n\t\treturn this.pool.get(index, dataIndex);\n\t}\n\tset(index: number, dataIndex: number, value: number) {\n\t\tlet array = this.pool.at(index);\n\t\tarray[dataIndex] = value;\n\t}\n\n\tdelete(index: number) {\n\t\tthis.pool.deleteIndex(index);\n\t}\n\tclear() {\n\t\tthis.pool.clear();\n\t}\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from '../world';\nimport type { 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 { ComponentMap } from '../../component-definition';\nimport type { ComponentSystemCallbacks, ComponentSystemWorld, EntityQueryComponents, EntityUpdateComponents, EntityUpdateFunction, QueryDelta, UpdateEntityConfigObject } from '../component-system';\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\n\tconstructor(updateFunction: EntityUpdateFunction<C, T, W, D>) {\n\t\tsuper();\n\t\tthis.updateFunction = updateFunction;\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\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<Record<string, unknown>> = [];\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(config: Record<string, unknown>) {\n\t\t\t\t\tcreatedEntities.push(config);\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 BaseWorld from '../world';\nimport type BaseEntity from '../entity';\nimport type { BaseComponent, ComponentDefinitionMap, ComponentMap, RegisteredComponentRegistry } 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} else {\n\t\t\tthis.worker = new ComponentWebWorker(options.updateFunction);\n\t\t\tthis.isWorkerThread = false;\n\t\t}\n\n\t\tthis.initWorker();\n\t}\n\n\tprivate initWorker() {\n\t\tthis.worker.onmessage = (e: MessageEvent) => {\n\t\t\tlet message = e.data as ComponentWorkerMessage;\n\t\t\tif(message.type === '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 === '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.\n\t\t\t\tmessage.created.forEach(config => {\n\t\t\t\t\tthis.world.loadEntity(config);\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};\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\tconst registry = this.world.registry as RegisteredComponentRegistry<C>;\n\t\t[\n\t\t\t...query.required,\n\t\t\t...query.optional ?? [],\n\t\t].forEach(componentName => {\n\t\t\tconst component = entity.components[componentName];\n\t\t\tconst memoryComponent = registry[componentName].memoryComponent;\n\t\t\tif(component && memoryComponent) {\n\t\t\t\tcomponents[componentName] = memoryComponent.getBlock(component.index) 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\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\nexport interface ComponentSystemWorld {\n\tgameTime: number\n\telapsedTime: number\n}\nexport type CreateEntityConfig = Record<string, unknown>;\n\nexport interface ComponentSystemCallbacks<C extends ComponentMap = ComponentMap> {\n\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]): void\n\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(config: CreateEntityConfig): 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\n\tqueries?: { [key: string]: ComponentSystemQuery<C> }\n}\n\nexport type { BaseComponent };\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { 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\tstatic eidCounter = 1;\n\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\tconstructor(world: BaseWorld<ComponentDefinitionMap, C, Cfg>, config?: Cfg) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.eid = BaseEntity.eidCounter++;\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 component = definition.load(this, memoryComponent, config);\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\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 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 { MAX_BYTE_OFFSET_LENGTH } from '@daneren2005/shared-memory-objects/utils/pointer';\nimport MemoryComponent from './memory-component';\nimport type BaseEntity from './entity';\nimport type System from './systems/system';\nimport EntitySystem from './systems/entity-system';\nimport ComponentSystem 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\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\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\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\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// 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\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":";;;;;;;;;;;;;;;CAEA,IAAI,IAAM,OAAO,UAAU,gBACvB,IAAS;CASb,SAAS,IAAS,CAAC;CASnB,AAAI,OAAO,WACT,EAAO,YAAY,OAAO,OAAO,IAAI,GAMhC,IAAI,EAAO,CAAC,CAAC,cAAW,IAAS;CAYxC,SAAS,EAAG,GAAI,GAAS,GAAM;EAG7B,AAFA,KAAK,KAAK,GACV,KAAK,UAAU,GACf,KAAK,OAAO,KAAQ;CACtB;CAaA,SAAS,EAAY,GAAS,GAAO,GAAI,GAAS,GAAM;EACtD,IAAI,OAAO,KAAO,YAChB,MAAU,UAAU,iCAAiC;EAGvD,IAAI,IAAW,IAAI,EAAG,GAAI,KAAW,GAAS,CAAI,GAC9C,IAAM,IAAS,IAAS,IAAQ;EAMpC,OAJK,EAAQ,QAAQ,KACX,EAAQ,QAAQ,EAAI,CAAC,KAC1B,EAAQ,QAAQ,KAAO,CAAC,EAAQ,QAAQ,IAAM,CAAQ,IADxB,EAAQ,QAAQ,EAAI,CAAC,KAAK,CAAQ,KAD1C,EAAQ,QAAQ,KAAO,GAAU,EAAQ,iBAI7D;CACT;CASA,SAAS,EAAW,GAAS,GAAK;EAChC,AAAI,EAAE,EAAQ,iBAAiB,IAAG,EAAQ,UAAU,IAAI,EAAO,IAC1D,OAAO,EAAQ,QAAQ;CAC9B;CASA,SAAS,IAAe;EAEtB,AADA,KAAK,UAAU,IAAI,EAAO,GAC1B,KAAK,eAAe;CACtB;CA+OA,AAtOA,EAAa,UAAU,aAAa,WAAsB;EACxD,IAAI,IAAQ,CAAC,GACT,GACA;EAEJ,IAAI,KAAK,iBAAiB,GAAG,OAAO;EAEpC,KAAK,KAAS,IAAS,KAAK,SAC1B,AAAI,EAAI,KAAK,GAAQ,CAAI,KAAG,EAAM,KAAK,IAAS,EAAK,MAAM,CAAC,IAAI,CAAI;EAOtE,OAJI,OAAO,wBACF,EAAM,OAAO,OAAO,sBAAsB,CAAM,CAAC,IAGnD;CACT,GASA,EAAa,UAAU,YAAY,SAAmB,GAAO;EAC3D,IAAI,IAAM,IAAS,IAAS,IAAQ,GAChC,IAAW,KAAK,QAAQ;EAE5B,IAAI,CAAC,GAAU,OAAO,CAAC;EACvB,IAAI,EAAS,IAAI,OAAO,CAAC,EAAS,EAAE;EAEpC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAS,QAAQ,IAAS,MAAM,CAAC,GAAG,IAAI,GAAG,KAC7D,EAAG,KAAK,EAAS,EAAE,CAAC;EAGtB,OAAO;CACT,GASA,EAAa,UAAU,gBAAgB,SAAuB,GAAO;EACnE,IAAI,IAAM,IAAS,IAAS,IAAQ,GAChC,IAAY,KAAK,QAAQ;EAI7B,OAFK,IACD,EAAU,KAAW,IAClB,EAAU,SAFM;CAGzB,GASA,EAAa,UAAU,OAAO,SAAc,GAAO,GAAI,GAAI,GAAI,GAAI,GAAI;EACrE,IAAI,IAAM,IAAS,IAAS,IAAQ;EAEpC,IAAI,CAAC,KAAK,QAAQ,IAAM,OAAO;EAE/B,IAAI,IAAY,KAAK,QAAQ,IACzB,IAAM,UAAU,QAChB,GACA;EAEJ,IAAI,EAAU,IAAI;GAGhB,QAFI,EAAU,QAAM,KAAK,eAAe,GAAO,EAAU,IAAI,KAAA,GAAW,EAAI,GAEpE,GAAR;IACE,KAAK,GAAG,OAAO,EAAU,GAAG,KAAK,EAAU,OAAO,GAAG;IACrD,KAAK,GAAG,OAAO,EAAU,GAAG,KAAK,EAAU,SAAS,CAAE,GAAG;IACzD,KAAK,GAAG,OAAO,EAAU,GAAG,KAAK,EAAU,SAAS,GAAI,CAAE,GAAG;IAC7D,KAAK,GAAG,OAAO,EAAU,GAAG,KAAK,EAAU,SAAS,GAAI,GAAI,CAAE,GAAG;IACjE,KAAK,GAAG,OAAO,EAAU,GAAG,KAAK,EAAU,SAAS,GAAI,GAAI,GAAI,CAAE,GAAG;IACrE,KAAK,GAAG,OAAO,EAAU,GAAG,KAAK,EAAU,SAAS,GAAI,GAAI,GAAI,GAAI,CAAE,GAAG;GAC3E;GAEA,KAAK,IAAI,GAAG,IAAW,MAAM,IAAK,CAAC,GAAG,IAAI,GAAK,KAC7C,EAAK,IAAI,KAAK,UAAU;GAG1B,EAAU,GAAG,MAAM,EAAU,SAAS,CAAI;EAC5C,OAAO;GACL,IAAI,IAAS,EAAU,QACnB;GAEJ,KAAK,IAAI,GAAG,IAAI,GAAQ,KAGtB,QAFI,EAAU,EAAE,CAAC,QAAM,KAAK,eAAe,GAAO,EAAU,EAAE,CAAC,IAAI,KAAA,GAAW,EAAI,GAE1E,GAAR;IACE,KAAK;KAAG,EAAU,EAAE,CAAC,GAAG,KAAK,EAAU,EAAE,CAAC,OAAO;KAAG;IACpD,KAAK;KAAG,EAAU,EAAE,CAAC,GAAG,KAAK,EAAU,EAAE,CAAC,SAAS,CAAE;KAAG;IACxD,KAAK;KAAG,EAAU,EAAE,CAAC,GAAG,KAAK,EAAU,EAAE,CAAC,SAAS,GAAI,CAAE;KAAG;IAC5D,KAAK;KAAG,EAAU,EAAE,CAAC,GAAG,KAAK,EAAU,EAAE,CAAC,SAAS,GAAI,GAAI,CAAE;KAAG;IAChE;KACE,IAAI,CAAC,GAAM,KAAK,IAAI,GAAG,IAAW,MAAM,IAAK,CAAC,GAAG,IAAI,GAAK,KACxD,EAAK,IAAI,KAAK,UAAU;KAG1B,EAAU,EAAE,CAAC,GAAG,MAAM,EAAU,EAAE,CAAC,SAAS,CAAI;GACpD;EAEJ;EAEA,OAAO;CACT,GAWA,EAAa,UAAU,KAAK,SAAY,GAAO,GAAI,GAAS;EAC1D,OAAO,EAAY,MAAM,GAAO,GAAI,GAAS,EAAK;CACpD,GAWA,EAAa,UAAU,OAAO,SAAc,GAAO,GAAI,GAAS;EAC9D,OAAO,EAAY,MAAM,GAAO,GAAI,GAAS,EAAI;CACnD,GAYA,EAAa,UAAU,iBAAiB,SAAwB,GAAO,GAAI,GAAS,GAAM;EACxF,IAAI,IAAM,IAAS,IAAS,IAAQ;EAEpC,IAAI,CAAC,KAAK,QAAQ,IAAM,OAAO;EAC/B,IAAI,CAAC,GAEH,OADA,EAAW,MAAM,CAAG,GACb;EAGT,IAAI,IAAY,KAAK,QAAQ;EAE7B,IAAI,EAAU,IAEV,EAAU,OAAO,MAChB,CAAC,KAAQ,EAAU,UACnB,CAAC,KAAW,EAAU,YAAY,MAEnC,EAAW,MAAM,CAAG;OAEjB;GACL,KAAK,IAAI,IAAI,GAAG,IAAS,CAAC,GAAG,IAAS,EAAU,QAAQ,IAAI,GAAQ,KAClE,CACE,EAAU,EAAE,CAAC,OAAO,KACnB,KAAQ,CAAC,EAAU,EAAE,CAAC,QACtB,KAAW,EAAU,EAAE,CAAC,YAAY,MAErC,EAAO,KAAK,EAAU,EAAE;GAO5B,AAAI,EAAO,SAAQ,KAAK,QAAQ,KAAO,EAAO,WAAW,IAAI,EAAO,KAAK,IACpE,EAAW,MAAM,CAAG;EAC3B;EAEA,OAAO;CACT,GASA,EAAa,UAAU,qBAAqB,SAA4B,GAAO;EAC7E,IAAI;EAUJ,OARI,KACF,IAAM,IAAS,IAAS,IAAQ,GAC5B,KAAK,QAAQ,MAAM,EAAW,MAAM,CAAG,MAE3C,KAAK,UAAU,IAAI,EAAO,GAC1B,KAAK,eAAe,IAGf;CACT,GAKA,EAAa,UAAU,MAAM,EAAa,UAAU,gBACpD,EAAa,UAAU,cAAc,EAAa,UAAU,IAK5D,EAAa,WAAW,GAKxB,EAAa,eAAe,GAKD,MAAvB,WACF,EAAO,UAAU;YExUE,IAArB,MAA0F;CACzF;CACA;CAEA,YAAY,GAAkB,GAAgC,GAAoB;EAEjF,AADA,KAAK,OAAO,GACZ,KAAK,OAAO,IAAI,EAAU,GAAM;GAC/B;GACA;EACD,CAAC;CACF;CAEA,IAAI,SAAS;EACZ,OAAO,KAAK,KAAK;CAClB;CACA,IAAI,YAAY;EACf,OAAO,KAAK,KAAK;CAClB;CAEA,OAAO,GAA+B;EACrC,OAAO,KAAK,KAAK,KAAK,CAAM;CAC7B;CAEA,SAAS,GAAkB;EAC1B,OAAO,KAAK,KAAK,GAAG,CAAK;CAC1B;CACA,IAAI,GAAe,GAA2B;EAC7C,OAAO,KAAK,KAAK,IAAI,GAAO,CAAS;CACtC;CACA,IAAI,GAAe,GAAmB,GAAe;EACpD,IAAI,IAAQ,KAAK,KAAK,GAAG,CAAK;EAC9B,EAAM,KAAa;CACpB;CAEA,OAAO,GAAe;EACrB,KAAK,KAAK,YAAY,CAAK;CAC5B;CACA,QAAQ;EACP,KAAK,KAAK,MAAM;CACjB;AACD,GCzC8B,IAA9B,cAAoF,EAAA,QAAa;CAChG;CACA;CACA,eAAuB;CACvB;CACA;CAEA,YAAY,GAA6C,IAAwB,EAAE,MAAM,SAAS,GAAG;EAOpG,AANA,MAAM,GAEN,KAAK,OAAO,EAAQ,MACpB,KAAK,QAAQ,GAEb,KAAK,mBAAmB,EAAQ,oBAAoB,GACpD,KAAK,WAAW,EAAQ,aAAa,KAAA,KAAY,EAAQ;CAC1D;CAEA,OAA6B,CAAC;CAE9B,QAAQ;EACP,KAAK,eAAe;CACrB;CAEA,gBAAsC,CAAC;CAEvC,OAAO,GAA8B;EAGpC,IAFA,KAAK,gBAAgB,GAElB,KAAK,gBAAgB,KAAK,oBAAoB,KAAK,UAAU;GAC/D,IAAI,IAAgB;GAWpB,OAVG,KAAK,mBAAmB,MAE1B,IAAgB,KAAK,eAAe,KAAK,mBAG1C,KAAK,IAAI,KAAK,eAAe,CAAa,GAC1C,KAAK,eAAe,GACpB,KAAK,WAAW,IAChB,KAAK,cAAc,GAEZ;EACR,OACC,OAAO;CAET;CAKA,gBAA0B;EACzB,KAAK,MAAM,yBAAyB,IAAI;CACzC;CAGA,qBAA8B;EAC7B,OAAO;CACR;CAEA,uBAA6C,CAAC;CAE9C,YAAqB;EACpB,OAAO;CACR;CAEA,UAAU;EACT,KAAK,mBAAmB;CACzB;AACD,GCpE8B,IAA9B,cAAgF,EAAU;CACzF,0BAAoC,CAAC;CACrC,8BAA6C;CAC7C;CACA;CAEA,YAAY,GAA6C,GAA+B;EAIvF,AAHA,MAAM,GAAO,CAAO,GAEpB,KAAK,qBAAqB,EAAQ,sBAAsB,GACxD,KAAK,gBAAgB,EAAQ,iBAAiB;CAC/C;CAEA,QAAQ;EAIP,AAHA,MAAM,MAAM,GAEZ,KAAK,0BAA0B,CAAC,GAChC,KAAK,8BAA8B;CACpC;CAEA,OAAO,GAA8B;EAUnC,OATE,KAAK,wBAAwB,UAC/B,KAAK,aAAa,KAAK,yBAAyB,KAAK,+BAA+B,CAAC,GACrF,KAAK,gBAAgB,GACjB,KAAK,wBAAwB,UAChC,KAAK,cAAc,GAGb,MAEA,MAAM,OAAO,CAAW;CAEjC;CACA,IAAI,GAA2B;EAC9B,IAAI,IAAY,KAAK,aAAa;EAClC,KAAK,aAAa,GAAW,CAAW;CACzC;CAGA,gBAA0B;EACtB,KAAK,wBAAwB,UAIhC,MAAM,cAAc;CACrB;CACA,qBAA8B;EAC7B,OAAO,KAAK,wBAAwB,SAAS;CAC9C;CAEA,aAAa,GAAqB,GAAqB;EACtD,IAAI,IAAU,YAAY,IAAI;EAC9B,KAAK,mBAAmB;EACxB,KAAI,IAAI,IAAI,GAAG,IAAI,EAAU,QAAQ,KAGpC,IAFA,KAAK,eAAe,EAAU,IAAI,CAAW,GAE1C,IAAI,KAAK,uBAAuB,KACxB,YAAY,IACnB,IAAM,KAAW,KAAK,eAAe;GAEvC,AADA,KAAK,0BAA0B,EAAU,MAAM,IAAI,CAAC,GACpD,KAAK,8BAA8B;GACnC;EACD;EAKF,AADA,KAAK,0BAA0B,CAAC,GAChC,KAAK,8BAA8B;CACpC;CACA,qBAAqB,CAAC;AAIvB,GCvE8B,IAA9B,cAAoH,EAAqB;CACxI,2BAA2B,IAAI,IAAI;CACnC;CAEA,YAAY,GAA6C,IAAiC,EAAE,MAAM,eAAe,GAAG;EAoBnH,AAnBA,AACC,EAAQ,uBAAqB,IAE9B,AACC,EAAQ,kBAAgB,GAGzB,MAAM,GAAO,CAAO,GACpB,KAAK,UAAU,GAEf,EAAM,GAAG,iBAAiB,MAA0B;GACnD,AAAG,KAAK,eAAe,CAAM,KAAK,KAAK,QAAQ,qBAC9C,KAAK,aAAa,GAAa,CAAC;EAElC,CAAC,GACD,EAAM,GAAG,mBAAmB,MAA0B;GACrD,KAAK,aAAa,CAAM;EACzB,CAAC,GAED,EAAM,SAAS,SAAQ,MAAU;GAChC,KAAK,eAAe,CAAM;EAC3B,CAAC;CACF;CAEA,eAAyB;EACxB,IAAM,IAAsB,CAAC;EAO7B,OANA,KAAK,SAAS,SAAQ,MAAU;GAC/B,AAAI,EAAO,WAAW,OAAO,QAC5B,EAAU,KAAK,CAAM;EAEvB,CAAC,GAEM;CACR;CACA,eAAe,GAAW,GAA2B;EACjD,EAAO,WAAW,OAAO,QAI5B,KAAK,aAAa,GAAQ,CAAW;CACtC;CACA,aAAa,GAAgC;EAC5C,OAAO,CAAC,EAAO,WAAW,OAAO;CAClC;CACA,iBAAiB,GAAuB;EACvC,OAAO,KAAK,SAAS,IAAI,EAAO,GAAG;CACpC;CAGA,eAAe,GAAgC;EAS7C,OARE,KAAK,QAAQ,cAAc,KAAK,QAAQ,WAAW,QAAO,MAAa,CAAC,CAAC,EAAO,WAAW,EAAU,CAAC,CAAC,WAAW,KAAK,QAAQ,WAAW,SACrI,KAGL,KAAK,aAAa,CAAM,KAC1B,KAAK,SAAS,IAAI,EAAO,KAAK,CAAW,GAClC,MAEA;CAET;CACA,aAAa,GAAuB;EACnC,KAAK,SAAS,OAAO,EAAO,GAAG;CAChC;CAEA,YAAqB;EACpB,OAAO,KAAK,SAAS,OAAO;CAC7B;AACD,GC9E8B,IAA9B,MAAwC;CAEvC,UAAU,GAAc,IAA6B,CAAC,GAAS,CAE/D;AACD,GCEqB,IAArB,cAAiL,EAAU;CAC1L;CACA,WAAuD,CAAC;CACxD,gBAA+E,CAAC;CAEhF;CAEA,YAAY,GAAkD;EAE7D,AADA,MAAM,GACN,KAAK,iBAAiB;CACvB;CAEA,YAAY,GAA6C;EACxD,IAAG,EAAQ,SAAS,QACnB,KAAK,eAAe,EACnB,MAAM,gBACP,CAAC;OACK,IAAG,EAAQ,SAAS,QAE1B,AADA,KAAK,iBAAiB,KAAK,eAAe,OAAO,EAAQ,IAAI,KAAK,KAAA,GAClE,KAAK,eAAe,EACnB,MAAM,SACP,CAAC;OACK,IAAG,EAAQ,SAAS,SAG1B,AADA,KAAK,WAAW,CAAC,GACjB,KAAK,gBAAgB,CAAC;OAChB,IAAG,EAAQ,SAAS,OAAO;GACjC,AAAG,KAAK,kBACP,OAAO,OAAO,EAAQ,OAAO,KAAK,cAAc;GAGjD,IAAM,IAAQ,YAAY,IAAI,GAC1B,IAAmC,CAAC,GACpC,IAA6B,CAAC,GAC9B,IAAkD,CAAC;GAEvD,KAAK,WAAW,EAAgB,KAAK,UAAU,EAAQ,QAAyB;GAEhF,IAAI,IAAoC,CAAC;GACzC,OAAO,QAAQ,EAAQ,OAAO,CAAC,CAAC,SAAS,CAAC,GAAU,OAAW;IAC9D,IAAM,IAAO,EAAgB,KAAK,cAAc,MAAa,CAAC,GAAG,CAAsB;IAEvF,AADA,KAAK,cAAc,KAAY,GAC/B,EAAQ,KAAY;GACrB,CAAC;GAED,IAAI,IAAyC;IAC5C,uBAAgE,GAAkB,GAAkB,GAAS,GAAgB;KAC5H,EAAa,KAAK;MACjB;MACA,OAAO;MACP,MAAM;OAAC;OAAe;OAAM;MAAK;KAClC,CAAC;IACF;IACA,gBAAgB,GAAkB,GAAe,GAAG,GAAsB;KACzE,EAAa,KAAK;MACjB;MACA;MACA;KACD,CAAC;IACF;IACA,gBAAgB,GAAe,GAAkB;KAChD,CAAC,EAAa,OAAW,EAAa,KAAS,CAAC,GAAA,CAAI,KAAK,CAAQ;IAClE;IACA,WAAW,GAAkB;KAC5B,EAAa,KAAK;MACjB;MACA,OAAO;MACP,MAAM,CAAC;KACR,CAAC;IACF;IACA,aAAa,GAAiC;KAC7C,EAAgB,KAAK,CAAM;IAC5B;GACD;GAQA,IAPG,KAAK,eAAe,UACtB,KAAK,eAAe,OAAO,EAAQ,OAAO,KAAK,UAAU,GAAS,CAAS,GAE5E,KAAK,SAAS,SAAQ,MAAU;IAC/B,KAAK,eAAe,EAAQ,OAAO,EAAO,UAAU,EAAO,YAAY,GAAS,CAAS;GAC1F,CAAC,GAEE,KAAK,eAAe,eACtB,KAAI,IAAI,KAAY,EAAQ,SAAS,SACpC,KAAK,eAAe,cAAc,EAAQ,OAAO,GAAU,CAAS;GAItE,IAAM,IAAU,YAAY,IAAI,IAAI;GAEpC,KAAK,eAAe;IACnB,MAAM;IACN,YAAY,EAAQ;IACpB;IACA,QAAQ;IACR;IACA,SAAS;GACV,CAAC;EACF;CACD;CAEA,eAAe,GAAuC;EACrD,KAAK,UAAU,EACd,MAAM,EACP,CAAC;CACF;AACD,GCzGM,IAAkB,WAKM,IAA9B,cAKU,EAAU;CACnB,2BAAuC,IAAI,IAAI;CAC/C;CAEA;CACA;CAEA,cAAsB;CACtB,cAAyC;CACzC,iBAA4C;CAC5C,qBAAgD;CAChD,YAAoB;CAEpB,aAAqB;CACrB,gBAAuE,CAAC;CAGxE,cAA6D,CAAC;CAI9D,YAAY,GAA6C,GAA4C;EA0BpG,AAzBA,MAAM,GAAO,CAAO,GACpB,KAAK,UAAU,GACf,OAAO,KAAK,KAAK,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,SAAQ,MAAa;GAC5D,KAAK,cAAc,qBAAa,IAAI,IAAI;EACzC,CAAC,GAED,EAAM,GAAG,iBAAiB,MAA0B;GACnD,KAAK,eAAe,CAAM;EAC3B,CAAC,GACD,EAAM,GAAG,mBAAmB,MAA0B;GACrD,KAAK,aAAa,CAAM;EACzB,CAAC,GAED,EAAM,SAAS,SAAQ,MAAU;GAChC,KAAK,eAAe,CAAM;EAC3B,CAAC,GAEE,CAAC,EAAQ,mBAA0B,WAAW,WAAW,UAAsB,WAAW,sBAAsB,UAClH,KAAK,SAAS,EAAQ,UAAU,GAChC,KAAK,iBAAiB,OAEtB,KAAK,SAAS,IAAI,EAAmB,EAAQ,cAAc,GAC3D,KAAK,iBAAiB,KAGvB,KAAK,WAAW;CACjB;CAEA,aAAqB;EA2DpB,AA1DA,KAAK,OAAO,aAAa,MAAoB;GAC5C,IAAI,IAAU,EAAE;GAChB,IAAG,EAAQ,SAAS,iBAEnB,AADA,KAAK,cAAc,IACnB,AAEC,KAAK,iBADL,KAAK,YAAY,QAAQ,GACN;QAEd,IAAG,EAAQ,SAAS,UAGzB,KAAK,oBADL,KAAK,eAAe,QAAQ,GACN;QAEjB,IAAG,EAAQ,SAAS,gBAAgB;IAE1C,IAAG,EAAQ,eAAe,KAAK,YAC9B;IAID,AADA,KAAK,YAAY,IACjB,KAAK,MAAM,KAAK,UAAU,KAAK,KAAK,mBAAmB,EAAQ,OAAO;IAItE,KAAI,IAAM,KAAS,OAAO,KAAK,EAAQ,YAAY,GAClD,KAAK,KAAK,GAAO,EAAQ,aAAa,EAAM;IAsB7C,AAnBA,EAAQ,OAAO,SAAQ,MAAS;KAE/B,IAAM,IAAS,KAAK,MAAM,eAAe,EAAM,QAAQ;KACvD,IAAG,CAAC,GAAQ;MACX,QAAQ,KAAK,GAAG,KAAK,KAAK,SAAS,EAAM,MAAM,kCAAkC,EAAM,UAAU;MACjG;KACD;KAEA,EAAO,KAAK,EAAM,OAAO,GAAG,EAAM,IAAI;IACvC,CAAC,GAGD,EAAQ,QAAQ,SAAQ,MAAU;KACjC,KAAK,MAAM,WAAW,CAAM;IAC7B,CAAC,GAED,KAAK,MAAM,KAAK,UAAU,KAAK,KAAK,0BAA0B,EAAQ,OAAO,GAC7E,KAAK,MAAM,yBAAyB,IAAI,GAExC,AAEC,KAAK,wBADL,KAAK,mBAAmB,QAAQ,GACN;GAE5B;EACD,GAMA,KAAK,OAAO,YAAY,EAHvB,MAAM,OAGiB,CAAO;CAChC;CAEA,OAA6B;EAC5B,IAAG,KAAK,aACP;EACM,IAAG,KAAK,aACd,OAAO,KAAK,YAAY;EAGzB,IAAI,EAAE,YAAS,eAAY,QAAQ,cAAoB;EAKvD,OAJA,KAAK,cAAc;GAClB;GACA;EACD,GACO;CACR;CAGA,gBAA+B;EAC9B,IAAI,EAAE,YAAS,eAAY,QAAQ,cAAoB;EAEvD,KAAK,iBAAiB;GACrB;GACA;EACD;EAEA,IAAM,IAAwC;GAC7C,MAAM;GACN,MAAM,KAAK,QAAQ,cAAc;EAClC;EAGA,OAFA,KAAK,OAAO,YAAY,CAAO,GAExB;CACR;CAGA,QAAQ;EAGP,IAFA,MAAM,MAAM,GAET,KAAK,aACJ,CAAC,KAAK,oBAAoB;GAC5B,IAAM,EAAE,YAAS,eAAY,QAAQ,cAAoB;GACzD,KAAK,qBAAqB;IAAE;IAAS;GAAQ;EAC9C;EAUD,AARA,KAAK,YAAY,IACjB,KAAK,cAEL,KAAK,SAAS,MAAM,GACpB,OAAO,OAAO,KAAK,aAAa,CAAC,CAAC,SAAQ,MAAQ,EAAK,MAAM,CAAC,GAC9D,KAAK,cAAc,CAAC,GAGpB,KAAK,OAAO,YAAY,EADkB,MAAM,QACxB,CAAO;CAChC;CAEA,OAAO,GAA8B;EAMnC,OALE,KAAK,aACP,KAAK,gBAAgB,GAEd,MAEA,MAAM,OAAO,CAAW;CAEjC;CAEA,gBAA0B,CAAC;CAC3B,qBAA8B;EAC7B,OAAO,KAAK;CACb;CACA,uBAA6C;EACxC,SAAK,WAGT;OAAG,CAAC,KAAK,oBAAoB;IAC5B,IAAM,EAAE,YAAS,eAAY,QAAQ,cAAoB;IACzD,KAAK,qBAAqB;KAAE;KAAS;IAAQ;GAC9C;GACA,OAAO,KAAK,mBAAmB;EAD/B;CAED;CACA,IAAI,GAA2B;EAC9B,IAAM,IAAQ;GACb,UAAU,KAAK,MAAM;GACrB;EACD;EAGA,AAFA,KAAK,iBAAiB,CAAK,GAE3B,KAAK,YAAY;EACjB,IAAI,IAAW,KAAK,gBAAgB,GAAiB,KAAK,OAAO,GAC7D,IAA4C,CAAC;EACjD,OAAO,QAAQ,KAAK,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAU,OAAW;GACzE,EAAQ,KAAY,KAAK,gBAAgB,GAAU,CAAK;EACzD,CAAC;EACD,IAAI,IAAqC;GACxC,MAAM;GACN,YAAY,KAAK;GACjB;GACA;GACA;EACD;EACA,KAAK,OAAO,YAAY,CAAO;CAChC;CAEA,gBAAwB,GAAmB,GAA+C;EACzF,IAAM,IAAQ,KAAK,cAAc,CAAS,GACpC,IAA4C,CAAC;EACnD,EAAM,MAAM,SAAQ,MAAU;GAC7B,EAAM,KAAK;IACV,UAAU,EAAO;IACjB,YAAY,KAAK,gBAAgB,GAAQ,CAAK;GAC/C,CAAC;EACF,CAAC;EACD,IAAM,IAAU,MAAM,KAAK,EAAM,OAAO;EAGxC,OAFA,KAAK,YAAY,KAAa;GAAE,uBAAO,IAAI,IAAI;GAAG,yBAAS,IAAI,IAAI;EAAE,GAE9D;GAAE;GAAO;EAAQ;CACzB;CACA,gBAAwB,GAAuB,GAAmC;EACjF,IAAM,IAAa,CAAC,GACd,IAAW,KAAK,MAAM;EAY5B,OAXA,CACC,GAAG,EAAM,UACT,GAAG,EAAM,YAAY,CAAC,CACvB,CAAC,CAAC,SAAQ,MAAiB;GAC1B,IAAM,IAAY,EAAO,WAAW,IAC9B,IAAkB,EAAS,EAAc,CAAC;GAChD,AAAG,KAAa,MACf,EAAW,KAAiB,EAAgB,SAAS,EAAU,KAAK;EAEtE,CAAC,GAEM;CACR;CAEA,iBAAiB,GAAuB;EACvC,OAAO,KAAK,SAAS,IAAI,EAAO,GAAG;CACpC;CACA,aAAqB,GAAuB,GAAyC;EAepF,OAJA,EAVG,EAAO,WAAW,OAAO,QAIzB,EAAM,SAAS,MAAK,MAAa,CAAC,EAAO,WAAW,EAAU,KAG9D,EAAM,KAAK,MAAK,MAAa,CAAC,CAAC,EAAO,WAAW,EAAU,KAG3D,EAAM,UAAU,CAAC,EAAM,OAAO,CAAM;CAKxC;CACA,cAAsB,GAAuC;EAC5D,IAAI,IAAQ,KAAK,YAAY;EAK7B,OAJA,AACC,MAAQ,KAAK,YAAY,KAAa;GAAE,uBAAO,IAAI,IAAI;GAAG,yBAAS,IAAI,IAAI;EAAE,GAGvE;CACR;CAEA,UAAkB,GAA2B,GAAuB;EAEnE,AADA,EAAM,QAAQ,OAAO,EAAO,GAAG,GAC/B,EAAM,MAAM,IAAI,CAAM;CACvB;CACA,YAAoB,GAA2B,GAAuB;EAClE,EAAM,MAAM,OAAO,CAAM,KAI5B,EAAM,QAAQ,IAAI,EAAO,GAAG;CAC7B;CACA,iBAAyB,GAAmB,GAAkC,GAAuB,GAAwB;EAC5H,IAAM,IAAQ,KAAK,cAAc,CAAS;EAC1C,AAAG,KACF,EAAK,IAAI,EAAO,KAAK,CAAM,GAC3B,KAAK,UAAU,GAAO,CAAM,KACnB,EAAK,OAAO,EAAO,GAAG,KAC/B,KAAK,YAAY,GAAO,CAAM;CAEhC;CAEA,eAAe,GAAgC;EAC9C,IAAM,IAAkB,KAAK,aAAa,GAAQ,KAAK,OAAO;EAQ9D,OAPA,KAAK,iBAAiB,GAAiB,KAAK,UAAU,GAAQ,CAAe,GAE7E,OAAO,QAAQ,KAAK,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAW,OAAW;GAC1E,IAAM,IAAY,KAAK,cAAc,OAAe,KAAK,cAAc,qBAAa,IAAI,IAAI;GAC5F,KAAK,iBAAiB,GAAW,GAAW,GAAQ,KAAK,aAAa,GAAQ,CAAK,CAAC;EACrF,CAAC,GAEM;CACR;CACA,aAAa,GAAuB;EAEnC,AADA,KAAK,iBAAiB,GAAiB,KAAK,UAAU,GAAQ,EAAK,GACnE,OAAO,QAAQ,KAAK,aAAa,CAAC,CAAC,SAAS,CAAC,GAAW,OAAU;GACjE,KAAK,iBAAiB,GAAW,GAAM,GAAQ,EAAK;EACrD,CAAC;CACF;CAEA,YAAqB;EACpB,OAAO,KAAK,SAAS,OAAO;CAC7B;CAEA,UAAU;EAGT,AAFA,MAAM,QAAQ,GAEX,eAAe,KAAK,UACtB,KAAK,OAAO,UAAU;CAExB;AACD,GChVqB,IAArB,MAAqB,UAAqE,EAAA,QAAa;CACtG,OAAO,aAAa;CAEpB;CACA;CAEA;CAEA,aAAuD,CAAC;CAExD,YAAY,GAAkD,GAAc;EAM3E,AALA,MAAM,GAEN,KAAK,QAAQ,GACb,KAAK,MAAM,EAAW,cACtB,KAAK,cAAc,UAAU,KAAU,CAAC,GAAG,EAAK,GAC7C,KACF,KAAK,KAAK,CAAM;CAElB;CAEA,cAAiC,GAAS,GAAa,IAAY,IAAY;EAC9E,IAAM,IAAc,KAAK,MAAM,SAA4C,IACrE,IAAkB,EAAW,iBAC7B,IAAY,EAAW,KAAK,MAAM,GAAiB,CAAM;EAM/D,OALA,KAAM,WAA0B,KAAQ,GACrC,KACF,KAAK,KAAK,mBAAmB,GAAM,CAAS,GAGtC;CACR;CACA,gBAAmC,GAAS;EAC3C,IAAM,IAAa,KAAK,WAA0B;EAClD,IAAG,GAAW;GACb,IAAM,IAAc,KAAK,MAAM,SAA4C;GAG3E,AAFA,KAAK,MAAM,yBAAyB,EAAW,iBAAiB,EAAU,OAAO,EAAW,aAAa,EAAW,KAAM,CAAS,IAAI,KAAA,CAAS,GAChJ,OAAO,KAAK,WAAW,IACvB,KAAK,KAAK,qBAAqB,CAAI;EACpC;CACD;CACA,aAAsD,GAAkB,GAAS,GAAgB;EAChG,IAAM,IAAY,KAAK,WAAW;EAC9B,MAIJ,EAA6C,KAAQ,GACrD,KAAK,KAAK,8BAA8B,GAAe,GAAM,CAAK;CACnE;CAIA,iBAAoC,GAAkB,GAAuB;EAC5E,IAAM,IAAY,KAAK,WAAW;EAC9B,KAIJ,OAAO,OAAO,GAAW,CAAM;CAChC;CACA,gBAAmC,GAAkB,GAAkB;EACtE,IAAM,IAAY,KAAK,WAAW;EAC9B,MAIJ,OAAQ,EAA4B,IACpC,KAAK,KAAK,8BAA8B,GAAe,CAAI;CAC5D;CAEA,2BAA2B;EAC1B,IAAM,IAAW,KAAK,MAAM,UACtB,IAAa,KAAK;EACxB,KAAI,IAAI,KAAQ,OAAO,KAAK,CAAU,GAAqB;GAC1D,IAAM,IAAa,EAAS,IACtB,IAAY,EAAW;GAC7B,AAAG,KACF,KAAK,MAAM,yBAAyB,EAAW,iBAAiB,EAAU,OAAO,EAAW,aAAa,EAAW,KAAM,CAAS,IAAI,KAAA,CAAS;EAElJ;CACD;CAEA,KAAK,GAAa;EACjB,IAAM,IAAQ,GACR,IAAW,KAAK,MAAM;EAC5B,KAAI,IAAI,KAAQ,OAAO,KAAK,CAAQ,GAAqB;GACxD,IAAG,MAAS,UACX;GAGD,IAAM,IAAa,EAAS;GACzB,EAAW,uBAGX,EAAW,eAAe,MAAK,MAAQ,KAAQ,CAAK,KACtD,KAAK,cAAc,GAAM,GAAQ,EAAK;EAExC;EAEA,KAAK,SAAS;CACf;CACA,OAAY;EACX,IAAM,IAAiC,CAAC,GAElC,IAAW,KAAK,MAAM,UACtB,IAAa,KAAK;EACxB,KAAI,IAAI,KAAQ,OAAO,KAAK,CAAU,GAAqB;GAC1D,IAAM,IAAa,EAAS,IACtB,IAAY,EAAW;GAC7B,AAAG,EAAW,QAAQ,KACrB,OAAO,OAAO,GAAQ,EAAW,KAAK,CAAS,CAAC;EAElD;EAEA,OAAO;CACR;CAGA,gBAAgB;EACf,IAAM,IAAS,KAAK;EACpB,IAAG,CAAC,GACH;EAGD,IAAM,IAAQ,GACR,IAAW,KAAK,MAAM;EAC5B,KAAI,IAAI,KAAQ,OAAO,KAAK,CAAQ,GAAqB;GACxD,IAAG,MAAS,UACX;GAGD,IAAM,IAAa,EAAS;GAC5B,AAAG,EAAW,uBAAuB,EAAW,eAAe,MAAK,MAAQ,KAAQ,CAAK,KACxF,KAAK,cAAc,GAAM,GAAQ,EAAK;EAExC;CACD;AACD,GC1IqB,IAArB,MAAqF;CACpF;CACA;CAEA,YAAY,IAAmC,CAAC,GAAG;EAClD,KAAK,UAAU;CAChB;CAEA,SAAS,GAAc,GAAa;EACnC,KAAK,QAAQ,KAAQ;CACtB;CAEA,UAAU,GAAkB;EAC3B,IAAM,IAAQ,GAA0C,MAClD,IAAO,IAAO,KAAK,QAAQ,KAAQ,KAAA;EACzC,OAAO,IAAO;GAAE,GAAG;GAAM,GAAG;EAAO,IAAI;CACxC;CAEA,WAAW,GAAa,IAAU,IAA0B;EAC3D,IAAM,IAAS,KAAK,aAAa,KAAK,UAAU,CAAM,CAAC;EACvD,OAAO,KAAK,MAAM,UAAU,GAAQ,CAAO;CAC5C;CAEA,aAAuB,GAAiC;EACvD,OAAO,IAAI,EAAmB,KAAK,OAAO,CAAM;CACjD;AACD,GChBM,IAAoB,GACpB,IAAuB,KA2BR,IAArB,cAIU,EAAA,QAAa;CACtB;CACA;CACA;CAIA,2BAA4C,IAAI,IAAI;CACpD,UAA4B,CAAC;CAE7B,WAAW;CAEX,aAAa;CACb,YAAY;CACZ,SAAS;CACT,YAAY;CAEZ,WAAW;CAIX,mBAAmD;EAAE,OAAO,CAAC;EAAG,gCAAgB,IAAI,IAAI;EAAG,aAAa;CAAE;CAC1G,iBAAiD;EAAE,OAAO,CAAC;EAAG,gCAAgB,IAAI,IAAI;EAAG,aAAa;CAAE;CAGxG,YAAY,GAAa,IAAgC,CAAC,GAAG;EAG5D,AAFA,MAAM,GAEN,KAAK,OAAO,IAAI,EAAW,EAAE,YAAY,EAAQ,YAAY,EAAkB,CAAC;EAEhF,IAAM,IAAgB;GAAE,GAAG;GAAU,QAAQ;EAAiB,GACxD,IAA0E,CAAC;EACjF,KAAI,IAAI,KAAQ,OAAO,KAAK,CAAa,GAAG;GAC3C,IAAM,IAAa,EAAc;GACjC,EAAU,KAAQ;IACjB,GAAG;IACH,iBAAiB,IAAI,EAAgB,KAAK,MAAM,EAAW,MAAM,EAAW,IAAI;GACjF;EACD;EAIA,AAHA,KAAK,WAAW,GAEhB,KAAK,UAAU,EAAQ,WAAW,IAAI,EAAsB,GAC5D,KAAK,QAAQ,QAAQ;CACtB;CAEA,MAAM,OAAO;EACZ,MAAM,QAAQ,IAAI,KAAK,QAAQ,KAAI,MAAU,EAAO,KAAK,CAAC,CAAC,CAAC,QAAO,MAAW,aAAmB,OAAO,CAAC;CAC1G;CACA,uBAA+B;EAC9B,OAAO,QAAQ,IAAI,KAAK,QAAQ,KAAI,MAAU,EAAO,cAAc,CAAC,CAAC,CAAC,QAAO,MAAW,aAAmB,OAAO,CAAC;CACpH;CAEA,UAAU,GAA4B,IAAU,IAA0B;EAqBzE,OApBA,KAAK,SAAS,IAAI,EAAO,KAAK,CAAM,GACpC,EAAO,QAAQ,MAEf,KAAK,WAAW,IAEhB,EAAO,GAAG,oBAAoB,MAAkB;GAC/C,KAAK,2BAA2B,GAAQ,CAAI;EAC7C,CAAC,GACD,EAAO,GAAG,sBAAsB,MAAkB;GACjD,KAAK,gCAAgC,GAAQ,CAAI;EAClD,CAAC,GAEE,MACF,EAAO,cAAc,GACrB,KAAK,KAAK,gBAAgB,CAAM,GAChC,EAAO,GAAG,eAAe;GACxB,KAAK,aAAa,CAAM;EACzB,CAAC,IAGK;CACR;CACA,WAAW,GAAa,IAAU,IAA0B;EAC3D,OAAO,KAAK,QAAQ,WAAW,GAAQ,CAAO;CAC/C;CAGA,KAAK,GAA0B;EAE9B,IAAG,CAAC,KAAK,UAAU;GAElB,KAAI,IAAI,KAAU,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC,GAClD,KAAK,aAAa,CAAM;GAGzB,AADA,KAAK,QAAQ,SAAQ,MAAU,EAAO,MAAM,CAAC,GAC7C,KAAK,gCAAgC;EACtC;EAEA,IAAM,IAAW,EAAO,SAAS,KAAI,MAAgB,KAAK,WAAW,GAAc,EAAK,CAAC;EACzF,KAAI,IAAI,KAAU,GAGjB,AAFA,EAAO,cAAc,GACrB,KAAK,KAAK,gBAAgB,CAAM,GAChC,EAAO,GAAG,eAAe;GACxB,KAAK,aAAa,CAAM;EACzB,CAAC;EAQF,AALA,KAAK,WAAW,EAAO,YAAY,GACnC,KAAK,aAAa,EAAO,cAAc,GACvC,KAAK,YAAY,EAAO,aAAa,GAGrC,KAAU,qBAAqB;CAChC;CACA,MAAM,QAAuB;EACzB,UAAK,UAIR;QAAI,IAAI,KAAU,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC,GAClD,KAAK,aAAa,CAAM;GAUzB,AARA,KAAK,QAAQ,SAAQ,MAAU,EAAO,MAAM,CAAC,GAC7C,MAAM,QAAQ,IACb,KAAK,QACH,KAAI,MAAU,EAAO,qBAAqB,CAAC,CAAC,CAC5C,QAAO,MAAW,aAAmB,OAAO,CAC/C,GACA,KAAK,sBAAsB,GAE3B,KAAK,WAAW;EAVS;CAW1B;CACA,aAAa,GAA4B;EAMxC,AAJG,KAAK,SAAS,OAAO,EAAO,GAAG,KACjC,KAAK,KAAK,kBAAkB,CAAM,GAGnC,EAAO,yBAAyB;CACjC;CACA,aAAa,GAA4B;EACxC,KAAK,aAAa,CAAM;CACzB;CACA,eAAe,GAA6C;EAC3D,OAAO,KAAK,SAAS,IAAI,CAAG;CAC7B;CAIA,yBAAyB,GAAkC,GAAe,GAAmB;EAC5F,KAAK,eAAe,MAAM,KAAK;GAAE;GAAiB;GAAO;EAAK,CAAC;CAChE;CAKA,yBAAyB,GAAmB;EAC3C,AAAG,KAAK,iBAAiB,eAAe,OAAO,CAAM,KAAK,KAAK,iBAAiB,eAAe,SAAS,KACvG,KAAK,mBAAmB;CAE1B;CACA,qBAA6B;EAE5B,OAAM,KAAK,iBAAiB,eAAe,SAAS,MAChD,KAAK,iBAAiB,MAAM,SAAS,KACvC,KAAK,aAAa,KAAK,gBAAgB,GAErC,KAAK,eAAe,MAAM,WAAW,KAGxC,KAAK,sBAAsB;CAE7B;CACA,wBAAgC;EAE/B,IAAM,IAAU,KAAK;EAErB,AADA,KAAK,mBAAmB,KAAK,gBAC7B,KAAK,iBAAiB;EAEtB,IAAM,IAAS,KAAK;EAEpB,AADA,EAAO,cAAc,GACrB,EAAO,eAAe,MAAM;EAC5B,KAAI,IAAI,KAAU,KAAK,SAGtB,CAAG,EAAO,UAAU,KAAK,EAAO,mBAAmB,MAClD,EAAO,eAAe,IAAI,CAAM;CAGnC;CAGA,kCAA0C;EAMzC,AALG,KAAK,iBAAiB,MAAM,SAAS,MACvC,KAAK,eAAe,MAAM,KAAK,GAAG,KAAK,iBAAiB,KAAK,GAC7D,KAAK,iBAAiB,MAAM,SAAS,IAEtC,KAAK,iBAAiB,eAAe,MAAM,GAC3C,KAAK,iBAAiB,cAAc;CACrC;CAGA,wBAAgC;EAM/B,AALA,KAAK,aAAa,KAAK,gBAAgB,GACvC,KAAK,aAAa,KAAK,cAAc,GACrC,KAAK,iBAAiB,eAAe,MAAM,GAC3C,KAAK,iBAAiB,cAAc,GACpC,KAAK,eAAe,eAAe,MAAM,GACzC,KAAK,eAAe,cAAc;CACnC;CACA,aAAqB,GAAgC;EACpD,KAAI,IAAI,KAAY,EAAO,OAE1B,AADA,EAAS,OAAO,GAChB,EAAS,gBAAgB,OAAO,EAAS,KAAK;EAE/C,EAAO,MAAM,SAAS;CACvB;CACA,uBAA+B,GAAqB;EACnD,IAAM,IAAS,KAAK;EACjB,MAAO,eAAe,SAAS,MAIlC,EAAO,eAAe,GACnB,EAAO,eAAe,IAAsB;GAC9C,IAAM,IAAQ,MAAM,KAAK,EAAO,cAAc,CAAC,CAAC,KAAI,MAAU,EAAO,IAAI,CAAC,CAAC,KAAK,IAAI;GAGpF,AAFA,QAAQ,KAAK,0DAA0D,EAAqB,mBAAmB,EAAM,iBAAiB,GACtI,EAAO,eAAe,MAAM,GAC5B,KAAK,mBAAmB;EACzB;CACD;CAEA,UAA+B,GAAc;EAG5C,OAFA,KAAK,QAAQ,KAAK,CAAM,GACxB,KAAK,KAAK,gBAAgB,CAAM,GACzB;CACR;CACA,qBAAqB,GAAmB;EAEvC,AADY,KAAK,QAAQ,WAAU,MAAe,EAAO,SAAS,EAAY,IAC3E,MAAU,OACZ,KAAK,QAAQ,KAAK,CAAM,GACxB,KAAK,KAAK,gBAAgB,CAAM;CAElC;CACA,aAAa,GAAc;EAC1B,IAAI,IAAQ,KAAK,QAAQ,WAAU,MAAU,EAAO,SAAS,CAAI;EACjE,IAAG,MAAU,IAAI;GAChB,IAAM,CAAC,KAAU,KAAK,QAAQ,OAAO,GAAO,CAAC;GAC7C,KAAK,KAAK,kBAAkB,CAAM;EACnC;CACD;CAEA,OAAO,GAAyD;EAC/D,KAAK,KAAK,kBAAkB,CAAW;EACvC,IAAM,IAAS,KAAK,UAAU,CAAW;EAGzC,OAFA,KAAK,KAAK,mBAAmB,CAAW,GAEjC;CACR;CACA,UAAkB,GAAyD;EAE1E,IADA,KAAK,cAAc,GAChB,KAAK,QACP,OAAO,CAAC;EAET,IAAM,IAAsB;EAM5B,AALA,IAAc,KAAK,YAAY,GAE/B,KAAK,YAAY,GAGjB,KAAK,mBAAmB;EAExB,IAAI,IAAgC;EA0BpC,OAzBA,KAAK,QAAQ,SAAQ,MAAU;GAC9B,IAAI,IAAY,IACZ,IAAM,IACN,IAAS;GACb,KAAK,KAAK,UAAU,EAAO,KAAK,SAAS;GACzC,IAAI;IAEH,AADA,IAAY,EAAO,UAAU,GAC1B,MACF,IAAM,EAAO,OAAO,CAAW;GAEjC,SAAQ,GAAG;IACV,IAAM,IAAQ;IAGd,AAFA,QAAQ,MAAM,EAAM,SAAS,CAAK,GAClC,IAAS,IACT,IAAkB;GACnB;GACA,KAAK,KAAK,UAAU,EAAO,KAAK,YAAY;IAC3C;IACA;IACA;GACD,CAAC;EACF,CAAC,GAED,KAAK,uBAAuB,CAAmB,GAExC,EACN,mBACD;CACD;CACA,QAAQ;EACP,KAAK,SAAS;CACf;CACA,SAAS;EACR,KAAK,SAAS;CACf;CAEA,2BAA2B,GAAuB,GAAoB;EACrE,KAAK,QAAQ,SAAQ,MAAU;GAC9B,CAAG,aAAkB,KAAgB,EAAO,QAAQ,YAAY,SAAS,CAAS,KAExE,aAAkB,KACxB,KAAK,gCAAgC,GAAQ,CAAS,MAFzD,EAAO,eAAe,CAAM;EAM9B,CAAC;CACF;CACA,gCAAgC,GAAuB,GAAoB;EAC1E,KAAK,QAAQ,SAAQ,MAAU;GAC9B,AAAG,aAAkB,KAAgB,EAAO,QAAQ,YAAY,SAAS,CAAS,IACjF,EAAO,aAAa,CAAM,IACjB,aAAkB,KACxB,KAAK,gCAAgC,GAAQ,CAAS,KACxD,EAAO,eAAe,CAAM;EAG/B,CAAC;CACF;CACA,gCAAwC,GAAiC,GAA6B;EACrG,IAAM,IAAmB,EAAO,QAAQ,SAAS,SAAS,CAAS,KAC/D,CAAC,CAAC,EAAO,QAAQ,KAAK,SAAS,CAAS,KACxC,CAAC,CAAC,EAAO,QAAQ,UAAU,SAAS,CAAS,GAC3C,IAAkB,OAAO,OAAO,EAAO,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,MAAK,MACjE,EAAM,SAAS,SAAS,CAAS,KACpC,CAAC,CAAC,EAAM,KAAK,SAAS,CAAS,KAC/B,CAAC,CAAC,EAAM,UAAU,SAAS,CAAS,CACxC;EAED,OAAO,KAAoB;CAC5B;CAEA,UAAU;EACN,AAOH,KAAK,eAHL,KAAK,QAAQ,SAAQ,MAAU;GAC9B,EAAO,QAAQ;EAChB,CAAC,GACgB;CAClB;AACD;;;ACvYA,SAAwB,EAAW,GAA0B;CAE5D,AADA,EAAO,WAAW,OAAO,OAAO,IAChC,EAAO,KAAK,OAAO;AACpB;;;ACDA,IAAa,IAAgC,KAkCvC,IAA4B;CAAE,KAAK;CAAG,KAAK;CAAG,KAAK;CAAG,SAAS;AAAE;AAGvE,SAAS,EAAU,GAAqC;CACvD,IAAG,CAAC,EAAQ,QACX,OAAO,EAAE,GAAG,EAAa;CAG1B,IAAI,IAAQ,GACR,IAAM,UACN,IAAM;CACV,KAAI,IAAI,KAAU,GAKjB,AAJA,KAAS,GACN,IAAS,MACX,IAAM,IAEJ,IAAS,MACX,IAAM;CAIR,OAAO;EACN,KAAK,IAAQ,EAAQ;EACrB;EACA;EACA,SAAS,EAAQ;CAClB;AACD;AAIA,IAAqB,IAArB,cAAsF,EAAA,QAAa;CAClG;CACA;CACA,QAA0B;EACzB,QAAQ,EAAE,GAAG,EAAa;EAC1B,SAAS,CAAC;EACV,QAAQ,EAAE,GAAG,EAAa;CAC3B;CAEA,QAAgB;CAChB,cAAsB;CACtB,cAAqC,CAAC;CACtC,gCAAwB,IAAI,IAA0B;CACtD,YAAoB;CAEpB,YAAY,GAA6C,IAAoC,CAAC,GAAG;EAUhG,AATA,MAAM,GAEN,KAAK,QAAQ,GACb,KAAK,sBAAsB,EAAQ,uBAAA,KAEnC,EAAM,GAAG,kBAAkB,KAAK,eAAe,GAC/C,EAAM,GAAG,mBAAmB,KAAK,gBAAgB,GACjD,EAAM,GAAG,gBAAgB,KAAK,aAAa,GAC3C,EAAM,GAAG,kBAAkB,KAAK,eAAe,GAC/C,EAAM,QAAQ,SAAQ,MAAU,KAAK,YAAY,CAAM,CAAC;CACzD;CAEA,eAAe,GAA6C;EAC3D,OAAO,KAAK,MAAM,QAAQ,MAAK,MAAU,EAAO,SAAS,CAAI;CAC9D;CAEA,QAAQ;EAQP,AAPA,KAAK,QAAQ,GACb,KAAK,cAAc,CAAC,GACpB,KAAK,cAAc,SAAQ,MAAU;GAGpC,AAFA,EAAO,MAAM,CAAC,GACd,EAAO,SAAS,CAAC,GACjB,EAAO,aAAa;EACrB,CAAC,GACD,KAAK,QAAQ;GACZ,QAAQ,EAAE,GAAG,EAAa;GAC1B,SAAS,CAAC;GACV,QAAQ,EAAE,GAAG,EAAa;EAC3B;CACD;CAEA,UAAU;EACN,KAAK,cAGR,KAAK,YAAY,IAEjB,KAAK,MAAM,IAAI,kBAAkB,KAAK,eAAe,GACrD,KAAK,MAAM,IAAI,mBAAmB,KAAK,gBAAgB,GACvD,KAAK,MAAM,IAAI,gBAAgB,KAAK,aAAa,GACjD,KAAK,MAAM,IAAI,kBAAkB,KAAK,eAAe,GACrD,MAAM,KAAK,KAAK,cAAc,KAAK,CAAC,CAAC,CAAC,SAAQ,MAAQ,KAAK,cAAc,CAAI,CAAC,GAC9E,KAAK,mBAAmB;CACzB;CAEA,wBAAgC;EAC/B,KAAK,cAAc,YAAY,IAAI;CACpC;CAEA,oBAA4B,MAAwB;EAChD,KAAK,MAAM,WAId,KAAK,YAAY,KAAK,YAAY,IAAI,IAAI,KAAK,WAAW,GAE1D,KAAK,SAAS,GACX,KAAK,SAAS,KAAK,uBACrB,KAAK,YAAY;CAEnB;CAEA,iBAAyB,MAAsB;EAC9C,KAAK,YAAY,CAAM;CACxB;CAEA,mBAA2B,MAAsB;EAChD,KAAK,cAAc,EAAO,IAAI;CAC/B;CAIA,YAAoB,GAAmB;EACtC,IAAG,KAAK,cAAc,IAAI,EAAO,IAAI,GACpC;EAGD,IAAM,IAAuB;GAC5B,KAAK,CAAC;GACN,QAAQ,CAAC;GACT,YAAY;GACZ,gBAAgB,MAAoB;IAEnC,AADA,EAAO,IAAI,KAAK,CAAO,GACvB,EAAO,aAAa,YAAY,IAAI;GACrC;GACA,wBAAwB;IACpB,EAAO,aAAa,MAIvB,EAAO,OAAO,KAAK,YAAY,IAAI,IAAI,EAAO,UAAU,GACxD,EAAO,aAAa;GACrB;EACD;EAIA,AAFA,KAAK,MAAM,GAAG,UAAU,EAAO,KAAK,mBAAmB,EAAO,aAAa,GAC3E,KAAK,MAAM,GAAG,UAAU,EAAO,KAAK,0BAA0B,EAAO,gBAAgB,GACrF,KAAK,cAAc,IAAI,EAAO,MAAM,CAAM;CAC3C;CAEA,cAAsB,GAAc;EACnC,IAAM,IAAS,KAAK,cAAc,IAAI,CAAI;EACtC,MAIJ,KAAK,MAAM,IAAI,UAAU,EAAK,mBAAmB,EAAO,aAAa,GACrE,KAAK,MAAM,IAAI,UAAU,EAAK,0BAA0B,EAAO,gBAAgB,GAC/E,KAAK,cAAc,OAAO,CAAI;CAC/B;CAEA,cAAsB;EACrB,IAAM,IAAU,KAAK,MAAM,QAAQ,KAAI,MAAU;GAChD,IAAM,IAAS,KAAK,cAAc,IAAI,EAAO,IAAI;GACjD,OAAO;IACN,MAAM,EAAO;IACb,KAAK,EAAU,GAAQ,OAAO,CAAC,CAAC;IAChC,QAAQ,EAAU,GAAQ,UAAU,CAAC,CAAC;GACvC;EACD,CAAC,GAEK,IAAsB,EAAE,GAAG,EAAa;EAqB9C,AApBA,EAAQ,SAAQ,MAAU;GAIzB,AAHA,EAAO,OAAO,EAAO,OAAO,KAC5B,EAAO,OAAO,EAAO,OAAO,KAC5B,EAAO,OAAO,EAAO,OAAO,KAC5B,EAAO,WAAW,EAAO,OAAO;EACjC,CAAC,GAED,KAAK,QAAQ;GACZ,QAAQ,EAAU,KAAK,WAAW;GAClC;GACA;EACD,GAEA,KAAK,QAAQ,GACb,KAAK,cAAc,CAAC,GACpB,KAAK,cAAc,SAAQ,MAAU;GAEpC,AADA,EAAO,MAAM,CAAC,GACd,EAAO,SAAS,CAAC;EAClB,CAAC,GAED,KAAK,KAAK,iBAAiB,KAAK,KAAK;CACtC;AACD"}
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,11 +1,14 @@
1
- import LocalPool from '@daneren2005/shared-memory-objects/local-pool';
1
+ import SharedPool from '@daneren2005/shared-memory-objects/shared-pool';
2
+ import type { SharedPoolMemory } from '@daneren2005/shared-memory-objects/shared-pool';
2
3
  import type MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';
3
4
  import type { TypedArrayConstructor } from '@daneren2005/shared-memory-objects/interfaces/typed-array-constructor';
4
5
  export type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;
5
6
  export default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {
6
7
  heap: MemoryHeap;
7
- pool: LocalPool<T>;
8
- constructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number);
8
+ pool: SharedPool<T>;
9
+ constructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number, memory?: SharedPoolMemory);
10
+ static fromSharedMemory<T extends ComponentTypedArray = ComponentTypedArray>(heap: MemoryHeap, memory: SharedPoolMemory): MemoryComponent<T>;
11
+ getSharedMemory(): SharedPoolMemory;
9
12
  get length(): number;
10
13
  get rawLength(): number;
11
14
  create(values: Array<number>): number;
@@ -38,6 +38,7 @@ export default abstract class ComponentSystem<C extends ComponentMap, T extends
38
38
  private updateEntityList;
39
39
  checkAddEntity(entity: BaseEntity<C>): boolean;
40
40
  removeEntity(entity: BaseEntity<C>): void;
41
+ recheckMembership(): void;
41
42
  shouldRun(): boolean;
42
43
  destroy(): void;
43
44
  }
@@ -68,17 +69,36 @@ export interface QueryDelta<T extends EntityUpdateComponents = EntityUpdateCompo
68
69
  added: Array<UpdateEntityConfigObject<T>>;
69
70
  removed: Array<number>;
70
71
  }
72
+ export interface WorkerAllocator {
73
+ allocateEid(): number;
74
+ allocateComponentBlock(name: string, values: Array<number>): number;
75
+ }
71
76
  export interface ComponentSystemWorld {
72
77
  gameTime: number;
73
78
  elapsedTime: number;
79
+ getString(pointer: number): string;
80
+ allocate?: WorkerAllocator;
81
+ buildEntityDescriptor?(config: WorkerCreateEntityConfig): WorkerCreatedEntity;
82
+ }
83
+ export type WorkerCreateEntityConfig = {
84
+ type: string;
85
+ } & {
86
+ [key: string]: unknown;
87
+ };
88
+ export interface WorkerCreatedEntity {
89
+ eid: number;
90
+ type: string;
91
+ isStatic?: boolean;
92
+ components: {
93
+ [name: string]: number;
94
+ };
74
95
  }
75
- export type CreateEntityConfig = Record<string, unknown>;
76
96
  export interface ComponentSystemCallbacks<C extends ComponentMap = ComponentMap> {
77
97
  entityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]): void;
78
98
  emitEntityEvent(entityId: number, event: string, ...args: Array<unknown>): void;
79
99
  emitSystemEvent(event: string, entityId: number): void;
80
100
  entityDied(entityId: number): void;
81
- createEntity(config: CreateEntityConfig): void;
101
+ createEntity(entity: WorkerCreatedEntity): void;
82
102
  }
83
103
  export interface ComponentSystemQuery<C extends ComponentMap = ComponentMap> {
84
104
  required: Array<keyof C>;
@@ -91,6 +111,7 @@ export interface ComponentSystemConfig<C extends ComponentMap, T extends EntityU
91
111
  getWorker: () => Worker;
92
112
  forceMainThread?: boolean;
93
113
  getInitData?: () => D;
114
+ createsEntities?: boolean;
94
115
  queries?: {
95
116
  [key: string]: ComponentSystemQuery<C>;
96
117
  };
@@ -1,13 +1,17 @@
1
1
  import WebWorker from './web-worker';
2
2
  import type ComponentWorkerMessage from './component-worker-message';
3
- import type { ComponentMap } from '../../component-definition';
3
+ import type BaseWorld from '../../world';
4
+ import type { ComponentDefinitionMap, ComponentMap } from '../../component-definition';
4
5
  import type { ComponentSystemWorld, EntityUpdateComponents, EntityUpdateFunction } from '../component-system';
5
6
  export default class ComponentWebWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld, D = unknown> extends WebWorker {
6
7
  private updateFunction;
7
8
  private entities;
8
9
  private queryEntities;
9
10
  private worldExtension;
10
- constructor(updateFunction: EntityUpdateFunction<C, T, W, D>);
11
+ private world;
12
+ private allocator;
13
+ private createsEntities;
14
+ constructor(updateFunction: EntityUpdateFunction<C, T, W, D>, world: BaseWorld<ComponentDefinitionMap, C>, createsEntities?: boolean);
11
15
  postMessage(message: ComponentWorkerMessage<W, D>): void;
12
16
  onMessageTyped(message: ComponentWorkerMessage<W, D>): void;
13
17
  }