@daneren2005/shared-memory-ecs 1.3.0 → 1.4.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/README.md CHANGED
@@ -10,10 +10,11 @@ fog of war, sub-classed entities, required components, etc).
10
10
  - **Component** – a plain object with an `index` (its block inside a shared-memory pool) plus getters/
11
11
  setters over that memory. Games decide what components exist.
12
12
  - **`ComponentDefinition`** – describes a component: its typed array `type`, block `size`, the config keys
13
- that trigger loading (`loadProperties`), a `load(entity, memory, config)` and an optional `save(component)`.
14
- A component's data splits into `Config` (defining props supplied up front, e.g. `maxHealth`) and
15
- `Serialization` (runtime-derived state, e.g. current `health`); `load` sees `Config & Serialization` while
16
- `save` returns only the `Serialization` slice.
13
+ that trigger loading (`loadProperties`), a `load(entity, memory, config)`, an optional `save(component)`,
14
+ and an optional `free(component)`. A component's data splits into `Config` (defining props supplied up
15
+ front, e.g. `maxHealth`) and `Serialization` (runtime-derived state, e.g. current `health`); `load` sees
16
+ `Config & Serialization` while `save` returns only the `Serialization` slice. `free` runs when the
17
+ component is torn down (see [Freeing extra resources](#freeing-extra-resources)).
17
18
  - **`ComponentRegistry<C>`** – the map of all component definitions for a game.
18
19
  - **`EntityFactory<C>`** – maps an entity `type` name to a base (template) config. Loading an entity layers
19
20
  the caller's config over its type's template, so shared static data lives in one place and a save only
@@ -334,6 +335,56 @@ thread already holds the values - sending them along would only pay to copy what
334
335
  System events are dispatched before the per-entity events of the same run, so an entity a run both moved and
335
336
  killed is still in the world when its move is reported.
336
337
 
338
+ ### Freeing component memory safely
339
+
340
+ Component blocks live in a shared pool, so a freed block gets handed straight back out to the next entity that
341
+ needs one. That is a problem across workers: if one system kills an entity, a second reuses its freed block for
342
+ a brand-new entity, and a third is still mid-run over what it thinks is the old entity, the third system writes
343
+ into the new entity's memory.
344
+
345
+ So the library never frees a block the instant it is orphaned. When an entity dies or you call
346
+ `removeComponent`, the block is *deferred* — the component is gone from the entity immediately, but the memory is
347
+ held until every system that could be mid-run over it has finished a run. Only then is the block returned to the
348
+ pool for reuse. This is automatic; there is nothing to call. The one visible effect is that
349
+ `memoryComponent.length` can briefly sit one higher than the number of live components, until the next update
350
+ lets the holding systems finish. If a system stays stuck (never completes a run) for more than ten seconds of
351
+ unscaled time, the world logs a warning naming that system and frees the blocks anyway rather than leak them —
352
+ a stuck system there is a bug worth chasing down.
353
+
354
+ ### Freeing extra resources
355
+
356
+ Everything above frees a component's own block. A component that allocates something *else* in `load` —
357
+ another heap structure (a `SharedList`, a `SharedString`) or child entities it owns — needs to release that
358
+ too, and the block-level deferred free won't do it. Give the definition an optional `free(component)`:
359
+
360
+ ```ts
361
+ const cargoDefinition: ComponentDefinition<Cargo, Uint32Array, CargoConfig> = {
362
+ type: Uint32Array,
363
+ size: 3,
364
+ loadProperties: ['cargoSpace'],
365
+ load(entity, memory, config) {
366
+ /* allocate a SharedList in the heap, stash its pointer in the block, return accessors */
367
+ },
368
+ free(component) {
369
+ component.items.free(); // release the SharedList + the item entities it holds
370
+ },
371
+ };
372
+ ```
373
+
374
+ `free` runs exactly once per component teardown: on `removeComponent`, and on every path that removes an
375
+ entity — `removeEntity`, a `death` (from `killEntity`), a `load` that drops the old batch, and `clear`.
376
+ It is deferred to the same safe point as the component's own block (see above), not fired the instant the
377
+ entity dies — so a system still mid-run over that memory can't see your resource released early. Reload calls
378
+ it without any `death` event, so it is the reliable place to avoid leaks when a world is reused.
379
+
380
+ ### Reusing a world: `load` and `clear`
381
+
382
+ A world is meant to be reused rather than rebuilt. `world.load(config)` swaps in a fresh scenario — it removes
383
+ the old entities, clears every system, and loads the new batch (deferred frees from the old contents drain over
384
+ the following updates, as above). `await world.clear()` instead tears the world all the way back down to an
385
+ empty, reusable state: it waits for every system's in-flight worker run to finish so nothing is still reading
386
+ the memory, frees the held blocks immediately, and resolves once the world is ready to load into again.
387
+
337
388
  ## Measuring performance
338
389
 
339
390
  `PerformanceTiming` watches a world and reports what running it costs. Hand it the world and it hooks itself
@@ -14,6 +14,7 @@ export interface ComponentDefinition<Component extends BaseComponent, T extends
14
14
  loadInFinishLoading?: boolean;
15
15
  load(entity: BaseEntity, memory: MemoryComponent<T>, config: Config & Serialization): Component;
16
16
  save?(component: Component): Serialization;
17
+ free?(component: Component): void;
17
18
  }
18
19
  export type RegisteredComponentDefinition<Component extends BaseComponent, T extends ComponentTypedArray = ComponentTypedArray, Config = any, Serialization = object> = ComponentDefinition<Component, T, Config, Serialization> & {
19
20
  memoryComponent: MemoryComponent<T>;
package/dist/index.js CHANGED
@@ -150,9 +150,16 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
150
150
  update(e) {
151
151
  if (this.currentDelta += e, this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {
152
152
  let e = 0;
153
- return this.deltaBetweenRuns > 0 && (e = this.currentDelta % this.deltaBetweenRuns), this.run(this.currentDelta - e), this.currentDelta = e, this.firstRun = !1, !0;
153
+ return this.deltaBetweenRuns > 0 && (e = this.currentDelta % this.deltaBetweenRuns), this.run(this.currentDelta - e), this.currentDelta = e, this.firstRun = !1, this.onRunFinished(), !0;
154
154
  } else return !1;
155
155
  }
156
+ onRunFinished() {
157
+ this.world.notifySystemRunCompleted(this);
158
+ }
159
+ isCurrentlyRunning() {
160
+ return !1;
161
+ }
162
+ waitForRunToComplete() {}
156
163
  shouldRun() {
157
164
  return !0;
158
165
  }
@@ -171,12 +178,18 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
171
178
  super.clear(), this.remainingInstancesToRun = [], this.remainingInstancesStartTime = null;
172
179
  }
173
180
  update(e) {
174
- return this.remainingInstancesToRun.length ? (this.runIterables(this.remainingInstancesToRun, this.remainingInstancesStartTime ?? 0), this.currentDelta += e, !0) : super.update(e);
181
+ return this.remainingInstancesToRun.length ? (this.runIterables(this.remainingInstancesToRun, this.remainingInstancesStartTime ?? 0), this.currentDelta += e, this.remainingInstancesToRun.length || this.onRunFinished(), !0) : super.update(e);
175
182
  }
176
183
  run(e) {
177
184
  let t = this.getIterables();
178
185
  this.runIterables(t, e);
179
186
  }
187
+ onRunFinished() {
188
+ this.remainingInstancesToRun.length || super.onRunFinished();
189
+ }
190
+ isCurrentlyRunning() {
191
+ return this.remainingInstancesToRun.length > 0;
192
+ }
180
193
  runIterables(e, t) {
181
194
  let n = performance.now();
182
195
  this.beforeRunIterables();
@@ -304,6 +317,7 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
304
317
  initialized = !1;
305
318
  initPromise = null;
306
319
  loadingPromise = null;
320
+ runCompletePromise = null;
307
321
  isRunning = !1;
308
322
  generation = 0;
309
323
  queryEntities = {};
@@ -337,7 +351,7 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
337
351
  t.emit(e.event, ...e.args);
338
352
  }), t.created.forEach((e) => {
339
353
  this.world.loadEntity(e);
340
- }), this.world.emit(`system-${this.name}-worker-events-finished`, t.runTime);
354
+ }), this.world.emit(`system-${this.name}-worker-events-finished`, t.runTime), this.world.notifySystemRunCompleted(this), this.runCompletePromise &&= (this.runCompletePromise.resolve(), null);
341
355
  }
342
356
  }, this.worker.postMessage({ type: "init" });
343
357
  }
@@ -363,11 +377,34 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
363
377
  return this.worker.postMessage(n), e;
364
378
  }
365
379
  clear() {
366
- super.clear(), this.isRunning = !1, this.generation++, this.entities.clear(), Object.values(this.queryEntities).forEach((e) => e.clear()), this.queryDeltas = {}, this.worker.postMessage({ type: "reset" });
380
+ if (super.clear(), this.isRunning && !this.runCompletePromise) {
381
+ let { promise: e, resolve: t } = Promise.withResolvers();
382
+ this.runCompletePromise = {
383
+ promise: e,
384
+ resolve: t
385
+ };
386
+ }
387
+ this.isRunning = !1, this.generation++, this.entities.clear(), Object.values(this.queryEntities).forEach((e) => e.clear()), this.queryDeltas = {}, this.worker.postMessage({ type: "reset" });
367
388
  }
368
389
  update(e) {
369
390
  return this.isRunning ? (this.currentDelta += e, !1) : super.update(e);
370
391
  }
392
+ onRunFinished() {}
393
+ isCurrentlyRunning() {
394
+ return this.isRunning;
395
+ }
396
+ waitForRunToComplete() {
397
+ if (this.isRunning) {
398
+ if (!this.runCompletePromise) {
399
+ let { promise: e, resolve: t } = Promise.withResolvers();
400
+ this.runCompletePromise = {
401
+ promise: e,
402
+ resolve: t
403
+ };
404
+ }
405
+ return this.runCompletePromise.promise;
406
+ }
407
+ }
371
408
  run(e) {
372
409
  let t = {
373
410
  gameTime: this.world.gameTime,
@@ -467,7 +504,10 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
467
504
  }
468
505
  removeComponent(e) {
469
506
  let t = this.components[e];
470
- t && (this.world.registry[e].memoryComponent.delete(t.index), delete this.components[e], this.emit("component-removed", e));
507
+ if (t) {
508
+ let n = this.world.registry[e];
509
+ this.world.deferComponentMemoryFree(n.memoryComponent, t.index, n.free ? () => n.free(t) : void 0), delete this.components[e], this.emit("component-removed", e);
510
+ }
471
511
  }
472
512
  setComponent(e, t, n) {
473
513
  let r = this.components[e];
@@ -482,10 +522,10 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
482
522
  n && (delete n[t], this.emit("component-property-deleted", e, t));
483
523
  }
484
524
  deleteAllComponentMemory() {
485
- let e = this.world.registry;
486
- for (let t of Object.keys(this.components)) {
487
- let n = this.components[t];
488
- n && e[t].memoryComponent.delete(n.index);
525
+ let e = this.world.registry, t = this.components;
526
+ for (let n of Object.keys(t)) {
527
+ let r = e[n], i = t[n];
528
+ i && this.world.deferComponentMemoryFree(r.memoryComponent, i.index, r.free ? () => r.free(i) : void 0);
489
529
  }
490
530
  }
491
531
  load(e) {
@@ -538,7 +578,7 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
538
578
  createEntity(e) {
539
579
  return new D(this.world, e);
540
580
  }
541
- }, k = c, A = class extends v.default {
581
+ }, k = c, A = 1e4, j = class extends v.default {
542
582
  heap;
543
583
  registry;
544
584
  factory;
@@ -549,6 +589,17 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
549
589
  timeScale = 1;
550
590
  paused = !1;
551
591
  destroyed = !1;
592
+ pristine = !0;
593
+ activeFreeBuffer = {
594
+ frees: [],
595
+ waitingSystems: /* @__PURE__ */ new Set(),
596
+ waitElapsed: 0
597
+ };
598
+ nextFreeBuffer = {
599
+ frees: [],
600
+ waitingSystems: /* @__PURE__ */ new Set(),
601
+ waitElapsed: 0
602
+ };
552
603
  constructor(e, t = {}) {
553
604
  super(), this.heap = new s({ bufferSize: t.heapSize ?? k });
554
605
  let n = {
@@ -571,7 +622,7 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
571
622
  return Promise.all(this.systems.map((e) => e.finishLoading()).filter((e) => e instanceof Promise));
572
623
  }
573
624
  addEntity(e, t = !0) {
574
- return this.entities.set(e.eid, e), e.world = this, e.on("component-added", (t) => {
625
+ return this.entities.set(e.eid, e), e.world = this, this.pristine = !1, e.on("component-added", (t) => {
575
626
  this.addEntityToComponentSystem(e, t);
576
627
  }), e.on("component-removed", (t) => {
577
628
  this.removeEntityFromComponentSystem(e, t);
@@ -583,14 +634,22 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
583
634
  return this.factory.loadEntity(e, t);
584
635
  }
585
636
  load(e) {
586
- for (let e of Array.from(this.entities.values())) this.removeEntity(e);
587
- this.systems.forEach((e) => e.clear());
637
+ if (!this.pristine) {
638
+ for (let e of Array.from(this.entities.values())) this.removeEntity(e);
639
+ this.systems.forEach((e) => e.clear()), this.consolidateFreeBuffersForReload();
640
+ }
588
641
  let t = e.entities.map((e) => this.loadEntity(e, !1));
589
642
  for (let e of t) e.finishLoading(), this.emit("entity-added", e), e.on("death", () => {
590
643
  this.onEntityDied(e);
591
644
  });
592
645
  this.gameTime = e.gameTime ?? 0, this.playerTime = e.playerTime ?? 0, this.timeScale = e.timeScale ?? 1, this.finishLoadingSystems();
593
646
  }
647
+ async clear() {
648
+ if (!this.pristine) {
649
+ for (let e of Array.from(this.entities.values())) this.removeEntity(e);
650
+ this.systems.forEach((e) => e.clear()), await Promise.all(this.systems.map((e) => e.waitForRunToComplete()).filter((e) => e instanceof Promise)), this.freeAllPendingBuffers(), this.pristine = !0;
651
+ }
652
+ }
594
653
  removeEntity(e) {
595
654
  this.entities.delete(e.eid) && this.emit("entity-removed", e), e.deleteAllComponentMemory();
596
655
  }
@@ -600,6 +659,43 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
600
659
  getEntityByEid(e) {
601
660
  return this.entities.get(e);
602
661
  }
662
+ deferComponentMemoryFree(e, t, n) {
663
+ this.nextFreeBuffer.frees.push({
664
+ memoryComponent: e,
665
+ index: t,
666
+ free: n
667
+ });
668
+ }
669
+ notifySystemRunCompleted(e) {
670
+ this.activeFreeBuffer.waitingSystems.delete(e) && this.activeFreeBuffer.waitingSystems.size === 0 && this.processFreeBuffers();
671
+ }
672
+ processFreeBuffers() {
673
+ for (; this.activeFreeBuffer.waitingSystems.size === 0 && (this.activeFreeBuffer.frees.length > 0 && this.performFrees(this.activeFreeBuffer), this.nextFreeBuffer.frees.length !== 0);) this.promoteNextFreeBuffer();
674
+ }
675
+ promoteNextFreeBuffer() {
676
+ let e = this.activeFreeBuffer;
677
+ this.activeFreeBuffer = this.nextFreeBuffer, this.nextFreeBuffer = e;
678
+ let t = this.activeFreeBuffer;
679
+ t.waitElapsed = 0, t.waitingSystems.clear();
680
+ for (let e of this.systems) (e.shouldRun() || e.isCurrentlyRunning()) && t.waitingSystems.add(e);
681
+ }
682
+ consolidateFreeBuffersForReload() {
683
+ this.activeFreeBuffer.frees.length > 0 && (this.nextFreeBuffer.frees.push(...this.activeFreeBuffer.frees), this.activeFreeBuffer.frees.length = 0), this.activeFreeBuffer.waitingSystems.clear(), this.activeFreeBuffer.waitElapsed = 0;
684
+ }
685
+ freeAllPendingBuffers() {
686
+ this.performFrees(this.activeFreeBuffer), this.performFrees(this.nextFreeBuffer), this.activeFreeBuffer.waitingSystems.clear(), this.activeFreeBuffer.waitElapsed = 0, this.nextFreeBuffer.waitingSystems.clear(), this.nextFreeBuffer.waitElapsed = 0;
687
+ }
688
+ performFrees(e) {
689
+ for (let t of e.frees) t.free?.(), t.memoryComponent.delete(t.index);
690
+ e.frees.length = 0;
691
+ }
692
+ checkFreeBufferTimeout(e) {
693
+ let t = this.activeFreeBuffer;
694
+ if (t.waitingSystems.size !== 0 && (t.waitElapsed += e, t.waitElapsed >= A)) {
695
+ let e = Array.from(t.waitingSystems).map((e) => e.name).join(", ");
696
+ console.warn(`shared-memory-ecs: deferred component free waited over ${A}ms on system(s): ${e}; freeing anyway`), t.waitingSystems.clear(), this.processFreeBuffers();
697
+ }
698
+ }
603
699
  addSystem(e) {
604
700
  return this.systems.push(e), this.emit("system-added", e), e;
605
701
  }
@@ -620,23 +716,24 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
620
716
  }
621
717
  runUpdate(e) {
622
718
  if (this.playerTime += e, this.paused) return {};
623
- e = this.timeScale * e, this.gameTime += e;
624
- let t = null;
625
- return this.systems.forEach((n) => {
719
+ let t = e;
720
+ e = this.timeScale * e, this.gameTime += e, this.processFreeBuffers();
721
+ let n = null;
722
+ return this.systems.forEach((t) => {
626
723
  let r = !0, i = !1, a = !1;
627
- this.emit(`system-${n.name}-started`);
724
+ this.emit(`system-${t.name}-started`);
628
725
  try {
629
- r = n.shouldRun(), r && (i = n.update(e));
726
+ r = t.shouldRun(), r && (i = t.update(e));
630
727
  } catch (e) {
631
- let n = e;
632
- console.error(n.message, n), a = !0, t = n;
728
+ let t = e;
729
+ console.error(t.message, t), a = !0, n = t;
633
730
  }
634
- this.emit(`system-${n.name}-finished`, {
731
+ this.emit(`system-${t.name}-finished`, {
635
732
  ran: i,
636
733
  shouldRun: r,
637
734
  failed: a
638
735
  });
639
- }), { lastSystemError: t };
736
+ }), this.checkFreeBufferTimeout(t), { lastSystemError: n };
640
737
  }
641
738
  pause() {
642
739
  this.paused = !0;
@@ -666,19 +763,19 @@ var u = Object.create, d = Object.defineProperty, f = Object.getOwnPropertyDescr
666
763
  };
667
764
  //#endregion
668
765
  //#region src/actions/kill-entity.ts
669
- function j(e) {
766
+ function M(e) {
670
767
  e.components.entity.dead = !0, e.emit("death");
671
768
  }
672
769
  //#endregion
673
770
  //#region src/performance-timing.ts
674
- var M = 1e3, N = {
771
+ var N = 1e3, P = {
675
772
  avg: 0,
676
773
  min: 0,
677
774
  max: 0,
678
775
  samples: 0
679
776
  };
680
- function P(e) {
681
- if (!e.length) return { ...N };
777
+ function F(e) {
778
+ if (!e.length) return { ...P };
682
779
  let t = 0, n = Infinity, r = 0;
683
780
  for (let i of e) t += i, i < n && (n = i), i > r && (r = i);
684
781
  return {
@@ -688,13 +785,13 @@ function P(e) {
688
785
  samples: e.length
689
786
  };
690
787
  }
691
- var F = class extends v.default {
788
+ var I = class extends v.default {
692
789
  world;
693
790
  ticksBetweenUpdates;
694
791
  stats = {
695
- update: { ...N },
792
+ update: { ...P },
696
793
  systems: [],
697
- events: { ...N }
794
+ events: { ...P }
698
795
  };
699
796
  ticks = 0;
700
797
  updateStart = 0;
@@ -711,9 +808,9 @@ var F = class extends v.default {
711
808
  this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
712
809
  e.run = [], e.events = [], e.eventStart = -1;
713
810
  }), this.stats = {
714
- update: { ...N },
811
+ update: { ...P },
715
812
  systems: [],
716
- events: { ...N }
813
+ events: { ...P }
717
814
  };
718
815
  }
719
816
  destroy() {
@@ -755,14 +852,14 @@ var F = class extends v.default {
755
852
  let t = this.systemTimings.get(e.name);
756
853
  return {
757
854
  name: e.name,
758
- run: P(t?.run ?? []),
759
- events: P(t?.events ?? [])
855
+ run: F(t?.run ?? []),
856
+ events: F(t?.events ?? [])
760
857
  };
761
- }), t = { ...N };
858
+ }), t = { ...P };
762
859
  e.forEach((e) => {
763
860
  t.avg += e.events.avg, t.min += e.events.min, t.max += e.events.max, t.samples += e.events.samples;
764
861
  }), this.stats = {
765
- update: P(this.updateTimes),
862
+ update: F(this.updateTimes),
766
863
  systems: e,
767
864
  events: t
768
865
  }, this.ticks = 0, this.updateTimes = [], this.systemTimings.forEach((e) => {
@@ -771,6 +868,6 @@ var F = class extends v.default {
771
868
  }
772
869
  };
773
870
  //#endregion
774
- export { D as BaseEntity, A as BaseWorld, E as ComponentSystem, w as ComponentWebWorker, t as DEAD_INDEX, M as DEFAULT_TICKS_BETWEEN_UPDATES, O as EntityFactory, S as EntitySystem, x as IterableSystem, y as MemoryComponent, F as PerformanceTiming, e as STATIC_INDEX, b as System, C as WebWorker, o as createComponentWorker, n as createEntityWorker, r as entityDefinition, j as killEntity, i as killEntityWorker };
871
+ export { D as BaseEntity, j as BaseWorld, E as ComponentSystem, w as ComponentWebWorker, t as DEAD_INDEX, N as DEFAULT_TICKS_BETWEEN_UPDATES, O as EntityFactory, S as EntitySystem, x as IterableSystem, y as MemoryComponent, I as PerformanceTiming, e as STATIC_INDEX, b as System, C as WebWorker, o as createComponentWorker, n as createEntityWorker, r as entityDefinition, M as killEntity, i as killEntityWorker };
775
872
 
776
873
  //# sourceMappingURL=index.js.map
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\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tabstract run(elapsedTime: number): void;\n\n\tshouldRun(): boolean {\n\t\treturn true;\n\t}\n\n\tdestroy() {\n\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\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn super.update(elapsedTime);\n\t\t}\n\t}\n\trun(elapsedTime: number): void {\n\t\tlet iterables = this.getIterables();\n\t\tthis.runIterables(iterables, elapsedTime);\n\t}\n\trunIterables(iterables: Array<T>, elapsedTime: number) {\n\t\tlet started = performance.now();\n\t\tthis.beforeRunIterables();\n\t\tfor(let i = 0; i < iterables.length; i++) {\n\t\t\tthis.updateIterable(iterables[i], elapsedTime);\n\n\t\t\tif(i % this.iterationsPerCheck === 0) {\n\t\t\t\tlet now = performance.now();\n\t\t\t\tif(now - started >= this.maxMsPerFrame) {\n\t\t\t\t\tthis.remainingInstancesToRun = iterables.slice(i + 1);\n\t\t\t\t\tthis.remainingInstancesStartTime = elapsedTime;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.remainingInstancesToRun = [];\n\t\tthis.remainingInstancesStartTime = null;\n\t}\n\tbeforeRunIterables() {}\n\n\tabstract getIterables(): Array<T>;\n\tabstract updateIterable(iterable: T, elapsedTime: number): void;\n}\n\nexport interface IterableSystemConfig extends SystemConfig {\n\titerationsPerCheck?: number\n\tmaxMsPerFrame?: number\n}\n","import type BaseWorld from '../world';\nimport type BaseEntity from '../entity';\nimport type { 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 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}\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\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\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[name];\n\t\tif(component) {\n\t\t\t(this.world.registry as RegisteredComponentRegistry<C>)[name].memoryComponent.delete(component.index);\n\t\t\tdelete this.components[name];\n\t\t\tthis.emit('component-removed', name);\n\t\t}\n\t}\n\tsetComponent<K extends keyof C, P extends keyof C[K]>(componentName: K, prop: P, value: C[K][P]) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\t(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\tfor(let name of Object.keys(this.components) as Array<keyof C>) {\n\t\t\tconst component = this.components[name];\n\t\t\tif(component) {\n\t\t\t\tregistry[name].memoryComponent.delete(component.index);\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;\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\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\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// Iterate over a copy since removeEntity mutates `this.entities`.\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\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\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\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\telapsedTime = this.timeScale * elapsedTime;\n\n\t\tthis.gameTime += elapsedTime;\n\n\t\tlet lastSystemError: Error | null = null;\n\t\tthis.systems.forEach(system => {\n\t\t\tlet shouldRun = true;\n\t\t\tlet ran = false;\n\t\t\tlet failed = false;\n\t\t\tthis.emit(`system-${system.name}-started`);\n\t\t\ttry {\n\t\t\t\tshouldRun = system.shouldRun();\n\t\t\t\tif(shouldRun) {\n\t\t\t\t\tran = system.update(elapsedTime);\n\t\t\t\t}\n\t\t\t} catch(e) {\n\t\t\t\tconst error = e as Error;\n\t\t\t\tconsole.error(error.message, error);\n\t\t\t\tfailed = true;\n\t\t\t\tlastSystemError = error;\n\t\t\t}\n\t\t\tthis.emit(`system-${system.name}-finished`, {\n\t\t\t\tran,\n\t\t\t\tshouldRun,\n\t\t\t\tfailed,\n\t\t\t});\n\t\t});\n\n\t\treturn {\n\t\t\tlastSystemError,\n\t\t};\n\t}\n\tpause() {\n\t\tthis.paused = true;\n\t}\n\tresume() {\n\t\tthis.paused = false;\n\t}\n\n\taddEntityToComponentSystem(entity: BaseEntity<C>, component: keyof C) {\n\t\tthis.systems.forEach(system => {\n\t\t\tif(system instanceof EntitySystem && system.options.components?.includes(component)) {\n\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t} else if(system instanceof ComponentSystem) {\n\t\t\t\tif(this.componentAffectsComponentSystem(system, component)) {\n\t\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\tremoveEntityFromComponentSystem(entity: BaseEntity<C>, component: keyof C) {\n\t\tthis.systems.forEach(system => {\n\t\t\tif(system instanceof EntitySystem && system.options.components?.includes(component)) {\n\t\t\t\tsystem.removeEntity(entity);\n\t\t\t} else if(system instanceof ComponentSystem) {\n\t\t\t\tif(this.componentAffectsComponentSystem(system, component)) {\n\t\t\t\t\tsystem.checkAddEntity(entity);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\tprivate componentAffectsComponentSystem(system: ComponentSystem<C, any>, component: keyof C): boolean {\n\t\tconst affectsMainQuery = system.options.required.includes(component)\n\t\t\t|| !!system.options.not?.includes(component)\n\t\t\t|| !!system.options.optional?.includes(component);\n\t\tconst affectsSubQuery = Object.values(system.options.queries ?? {}).some(query => {\n\t\t\treturn query.required.includes(component)\n\t\t\t\t|| !!query.not?.includes(component)\n\t\t\t\t|| !!query.optional?.includes(component);\n\t\t});\n\n\t\treturn affectsMainQuery || affectsSubQuery;\n\t}\n\n\tdestroy() {\n\t\tif(this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.systems.forEach(system => {\n\t\t\tsystem.destroy();\n\t\t});\n\t\tthis.destroyed = true;\n\t}\n}\n","import type BaseEntity from '../entity';\n\n// Flags the entity dead in shared memory and emits `death`; BaseWorld listens for it to remove the entity.\nexport default function killEntity(entity: BaseEntity): void {\n\tentity.components.entity.dead = true;\n\tentity.emit('death');\n}\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { ComponentDefinitionMap, ComponentMap } from './component-definition';\nimport type System from './systems/system';\n\nexport const DEFAULT_TICKS_BETWEEN_UPDATES = 1_000;\n\nexport interface TimingStats {\n\tavg: number\n\tmin: number\n\tmax: number\n\tsamples: number\n}\n\nexport interface SystemTimingStats {\n\tname: string\n\trun: TimingStats\n\tevents: TimingStats\n}\n\nexport interface PerformanceStats {\n\tupdate: TimingStats\n\tsystems: Array<SystemTimingStats>\n\tevents: TimingStats\n}\n\nexport interface PerformanceTimingOptions {\n\tticksBetweenUpdates?: number\n}\n\ninterface SystemTiming {\n\trun: Array<number>\n\tevents: Array<number>\n\t// -1 when no run is being dispatched.\n\teventStart: number\n\tonRunFinished: (runTime: number) => void\n\tonEventsFinished: () => void\n}\n\nconst EMPTY_TIMING: TimingStats = { avg: 0, min: 0, max: 0, samples: 0 };\n\n// An empty window reads as zeroes (not an infinite min) so a snapshot is always safe to render.\nfunction summarize(samples: Array<number>): TimingStats {\n\tif(!samples.length) {\n\t\treturn { ...EMPTY_TIMING };\n\t}\n\n\tlet total = 0;\n\tlet min = Infinity;\n\tlet max = 0;\n\tfor(let sample of samples) {\n\t\ttotal += sample;\n\t\tif(sample < min) {\n\t\t\tmin = sample;\n\t\t}\n\t\tif(sample > max) {\n\t\t\tmax = sample;\n\t\t}\n\t}\n\n\treturn {\n\t\tavg: total / samples.length,\n\t\tmin,\n\t\tmax,\n\t\tsamples: samples.length,\n\t};\n}\n\n// Watches a world and reports what it costs to run, driven off events the world emits. Emits `stats-updated`\n// every `ticksBetweenUpdates`; paused frames are skipped.\nexport default class PerformanceTiming<C extends ComponentMap = ComponentMap> extends EventEmitter {\n\tworld: BaseWorld<ComponentDefinitionMap, C>;\n\tticksBetweenUpdates: number;\n\tstats: PerformanceStats = {\n\t\tupdate: { ...EMPTY_TIMING },\n\t\tsystems: [],\n\t\tevents: { ...EMPTY_TIMING },\n\t};\n\n\tprivate ticks = 0;\n\tprivate updateStart = 0;\n\tprivate updateTimes: Array<number> = [];\n\tprivate systemTimings = new Map<string, SystemTiming>();\n\tprivate destroyed = false;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: PerformanceTimingOptions = {}) {\n\t\tsuper();\n\n\t\tthis.world = world;\n\t\tthis.ticksBetweenUpdates = options.ticksBetweenUpdates ?? DEFAULT_TICKS_BETWEEN_UPDATES;\n\n\t\tworld.on('update-started', this.onUpdateStarted);\n\t\tworld.on('update-finished', this.onUpdateFinished);\n\t\tworld.on('system-added', this.onSystemAdded);\n\t\tworld.on('system-removed', this.onSystemRemoved);\n\t\tworld.systems.forEach(system => this.trackSystem(system));\n\t}\n\n\tgetSystemStats(name: string): SystemTimingStats | undefined {\n\t\treturn this.stats.systems.find(system => system.name === name);\n\t}\n\n\treset() {\n\t\tthis.ticks = 0;\n\t\tthis.updateTimes = [];\n\t\tthis.systemTimings.forEach(timing => {\n\t\t\ttiming.run = [];\n\t\t\ttiming.events = [];\n\t\t\ttiming.eventStart = -1;\n\t\t});\n\t\tthis.stats = {\n\t\t\tupdate: { ...EMPTY_TIMING },\n\t\t\tsystems: [],\n\t\t\tevents: { ...EMPTY_TIMING },\n\t\t};\n\t}\n\n\tdestroy() {\n\t\tif(this.destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.destroyed = true;\n\n\t\tthis.world.off('update-started', this.onUpdateStarted);\n\t\tthis.world.off('update-finished', this.onUpdateFinished);\n\t\tthis.world.off('system-added', this.onSystemAdded);\n\t\tthis.world.off('system-removed', this.onSystemRemoved);\n\t\tArray.from(this.systemTimings.keys()).forEach(name => this.untrackSystem(name));\n\t\tthis.removeAllListeners();\n\t}\n\n\tprivate onUpdateStarted = () => {\n\t\tthis.updateStart = performance.now();\n\t};\n\n\tprivate onUpdateFinished = (elapsedTime: number) => {\n\t\tif(this.world.paused) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateTimes.push(performance.now() - this.updateStart);\n\n\t\tthis.ticks += elapsedTime;\n\t\tif(this.ticks >= this.ticksBetweenUpdates) {\n\t\t\tthis.recalculate();\n\t\t}\n\t};\n\n\tprivate onSystemAdded = (system: System<C>) => {\n\t\tthis.trackSystem(system);\n\t};\n\n\tprivate onSystemRemoved = (system: System<C>) => {\n\t\tthis.untrackSystem(system.name);\n\t};\n\n\t// The gap between `-worker-finished` (before events dispatch) and `-worker-events-finished` (after) is what\n\t// that run cost this thread. Both fire for the main-thread fallback too.\n\tprivate trackSystem(system: System<C>) {\n\t\tif(this.systemTimings.has(system.name)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst timing: SystemTiming = {\n\t\t\trun: [],\n\t\t\tevents: [],\n\t\t\teventStart: -1,\n\t\t\tonRunFinished: (runTime: number) => {\n\t\t\t\ttiming.run.push(runTime);\n\t\t\t\ttiming.eventStart = performance.now();\n\t\t\t},\n\t\t\tonEventsFinished: () => {\n\t\t\t\tif(timing.eventStart < 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttiming.events.push(performance.now() - timing.eventStart);\n\t\t\t\ttiming.eventStart = -1;\n\t\t\t},\n\t\t};\n\n\t\tthis.world.on(`system-${system.name}-worker-finished`, timing.onRunFinished);\n\t\tthis.world.on(`system-${system.name}-worker-events-finished`, timing.onEventsFinished);\n\t\tthis.systemTimings.set(system.name, timing);\n\t}\n\n\tprivate untrackSystem(name: string) {\n\t\tconst timing = this.systemTimings.get(name);\n\t\tif(!timing) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.world.off(`system-${name}-worker-finished`, timing.onRunFinished);\n\t\tthis.world.off(`system-${name}-worker-events-finished`, timing.onEventsFinished);\n\t\tthis.systemTimings.delete(name);\n\t}\n\n\tprivate recalculate() {\n\t\tconst systems = this.world.systems.map(system => {\n\t\t\tconst timing = this.systemTimings.get(system.name);\n\t\t\treturn {\n\t\t\t\tname: system.name,\n\t\t\t\trun: summarize(timing?.run ?? []),\n\t\t\t\tevents: summarize(timing?.events ?? []),\n\t\t\t};\n\t\t});\n\n\t\tconst events: TimingStats = { ...EMPTY_TIMING };\n\t\tsystems.forEach(system => {\n\t\t\tevents.avg += system.events.avg;\n\t\t\tevents.min += system.events.min;\n\t\t\tevents.max += system.events.max;\n\t\t\tevents.samples += system.events.samples;\n\t\t});\n\n\t\tthis.stats = {\n\t\t\tupdate: summarize(this.updateTimes),\n\t\t\tsystems,\n\t\t\tevents,\n\t\t};\n\n\t\tthis.ticks = 0;\n\t\tthis.updateTimes = [];\n\t\tthis.systemTimings.forEach(timing => {\n\t\t\ttiming.run = [];\n\t\t\ttiming.events = [];\n\t\t});\n\n\t\tthis.emit('stats-updated', this.stats);\n\t}\n}\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../node_modules/eventemitter3/index.js","../node_modules/eventemitter3/index.mjs","../src/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":"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"}
@@ -12,6 +12,7 @@ export default abstract class ComponentSystem<C extends ComponentMap, T extends
12
12
  private initialized;
13
13
  private initPromise;
14
14
  private loadingPromise;
15
+ private runCompletePromise;
15
16
  private isRunning;
16
17
  private generation;
17
18
  private queryEntities;
@@ -23,6 +24,9 @@ export default abstract class ComponentSystem<C extends ComponentMap, T extends
23
24
  finishLoading(): Promise<void>;
24
25
  clear(): void;
25
26
  update(elapsedTime: number): boolean;
27
+ protected onRunFinished(): void;
28
+ isCurrentlyRunning(): boolean;
29
+ waitForRunToComplete(): void | Promise<void>;
26
30
  run(elapsedTime: number): void;
27
31
  private buildQueryDelta;
28
32
  private buildComponents;
@@ -10,6 +10,8 @@ export default abstract class IterableSystem<C extends ComponentMap, T> extends
10
10
  clear(): void;
11
11
  update(elapsedTime: number): boolean;
12
12
  run(elapsedTime: number): void;
13
+ protected onRunFinished(): void;
14
+ isCurrentlyRunning(): boolean;
13
15
  runIterables(iterables: Array<T>, elapsedTime: number): void;
14
16
  beforeRunIterables(): void;
15
17
  abstract getIterables(): Array<T>;
@@ -13,6 +13,9 @@ export default abstract class System<C extends ComponentMap = ComponentMap> exte
13
13
  finishLoading(): void | Promise<void>;
14
14
  update(elapsedTime: number): boolean;
15
15
  abstract run(elapsedTime: number): void;
16
+ protected onRunFinished(): void;
17
+ isCurrentlyRunning(): boolean;
18
+ waitForRunToComplete(): void | Promise<void>;
16
19
  shouldRun(): boolean;
17
20
  destroy(): void;
18
21
  }
package/dist/world.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { EventEmitter } from 'eventemitter3';
2
2
  import MemoryHeap from '@daneren2005/shared-memory-objects/memory-heap';
3
+ import MemoryComponent from './memory-component';
3
4
  import type BaseEntity from './entity';
4
5
  import type System from './systems/system';
5
6
  import type { ComponentDefinitionMap, ComponentMap, ComponentsOf, EntityConfigOf, RegisteredComponentDefinition, RegisteredComponentRegistry } from './component-definition';
@@ -28,15 +29,27 @@ export default class BaseWorld<R extends ComponentDefinitionMap = ComponentDefin
28
29
  timeScale: number;
29
30
  paused: boolean;
30
31
  destroyed: boolean;
32
+ pristine: boolean;
33
+ private activeFreeBuffer;
34
+ private nextFreeBuffer;
31
35
  constructor(registry: R, options?: WorldOptions<C, Cfg>);
32
36
  init(): Promise<void>;
33
37
  private finishLoadingSystems;
34
38
  addEntity(entity: BaseEntity<C, Cfg>, created?: boolean): BaseEntity<C, Cfg>;
35
39
  loadEntity(config: Cfg, created?: boolean): BaseEntity<C, Cfg>;
36
40
  load(config: WorldConfig<Cfg>): void;
41
+ clear(): Promise<void>;
37
42
  removeEntity(entity: BaseEntity<C, Cfg>): void;
38
43
  onEntityDied(entity: BaseEntity<C, Cfg>): void;
39
44
  getEntityByEid(eid: number): BaseEntity<C, Cfg> | undefined;
45
+ deferComponentMemoryFree(memoryComponent: MemoryComponent, index: number, free?: () => void): void;
46
+ notifySystemRunCompleted(system: System<C>): void;
47
+ private processFreeBuffers;
48
+ private promoteNextFreeBuffer;
49
+ private consolidateFreeBuffersForReload;
50
+ private freeAllPendingBuffers;
51
+ private performFrees;
52
+ private checkFreeBufferTimeout;
40
53
  addSystem<T extends System<C>>(system: T): T;
41
54
  addSystemIfNotExists(system: System<C>): void;
42
55
  removeSystem(name: string): void;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@daneren2005/shared-memory-ecs",
3
3
  "description": "A small, reusable Entity/Component/System core backed by shared memory.",
4
4
  "author": "Scott Jackson",
5
- "version": "1.3.0",
5
+ "version": "1.4.0",
6
6
  "type": "module",
7
7
  "sideEffects": false,
8
8
  "repository": {