@daneren2005/shared-memory-ecs 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +146 -51
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -1,11 +1,106 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var
|
|
1
|
+
import { LocalPool as e, MAX_BYTE_OFFSET_LENGTH as t, MemoryHeap as n } from "@daneren2005/shared-memory-objects";
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var r = Object.create, i = Object.defineProperty, a = Object.getOwnPropertyDescriptor, o = Object.getOwnPropertyNames, s = Object.getPrototypeOf, c = Object.prototype.hasOwnProperty, l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), u = (e, t, n, r) => {
|
|
4
|
+
if (t && typeof t == "object" || typeof t == "function") for (var s = o(t), l = 0, u = s.length, d; l < u; l++) d = s[l], !c.call(e, d) && d !== n && i(e, d, {
|
|
5
|
+
get: ((e) => t[e]).bind(null, d),
|
|
6
|
+
enumerable: !(r = a(t, d)) || r.enumerable
|
|
7
|
+
});
|
|
8
|
+
return e;
|
|
9
|
+
}, d = /* @__PURE__ */ ((e, t, n) => (n = e == null ? {} : r(s(e)), u(t || !e || !e.__esModule ? i(n, "default", {
|
|
10
|
+
value: e,
|
|
11
|
+
enumerable: !0
|
|
12
|
+
}) : n, e)))((/* @__PURE__ */ l(((e, t) => {
|
|
13
|
+
var n = Object.prototype.hasOwnProperty, r = "~";
|
|
14
|
+
function i() {}
|
|
15
|
+
Object.create && (i.prototype = Object.create(null), new i().__proto__ || (r = !1));
|
|
16
|
+
function a(e, t, n) {
|
|
17
|
+
this.fn = e, this.context = t, this.once = n || !1;
|
|
18
|
+
}
|
|
19
|
+
function o(e, t, n, i, o) {
|
|
20
|
+
if (typeof n != "function") throw TypeError("The listener must be a function");
|
|
21
|
+
var s = new a(n, i || e, o), c = r ? r + t : t;
|
|
22
|
+
return e._events[c] ? e._events[c].fn ? e._events[c] = [e._events[c], s] : e._events[c].push(s) : (e._events[c] = s, e._eventsCount++), e;
|
|
23
|
+
}
|
|
24
|
+
function s(e, t) {
|
|
25
|
+
--e._eventsCount === 0 ? e._events = new i() : delete e._events[t];
|
|
26
|
+
}
|
|
27
|
+
function c() {
|
|
28
|
+
this._events = new i(), this._eventsCount = 0;
|
|
29
|
+
}
|
|
30
|
+
c.prototype.eventNames = function() {
|
|
31
|
+
var e = [], t, i;
|
|
32
|
+
if (this._eventsCount === 0) return e;
|
|
33
|
+
for (i in t = this._events) n.call(t, i) && e.push(r ? i.slice(1) : i);
|
|
34
|
+
return Object.getOwnPropertySymbols ? e.concat(Object.getOwnPropertySymbols(t)) : e;
|
|
35
|
+
}, c.prototype.listeners = function(e) {
|
|
36
|
+
var t = r ? r + e : e, n = this._events[t];
|
|
37
|
+
if (!n) return [];
|
|
38
|
+
if (n.fn) return [n.fn];
|
|
39
|
+
for (var i = 0, a = n.length, o = Array(a); i < a; i++) o[i] = n[i].fn;
|
|
40
|
+
return o;
|
|
41
|
+
}, c.prototype.listenerCount = function(e) {
|
|
42
|
+
var t = r ? r + e : e, n = this._events[t];
|
|
43
|
+
return n ? n.fn ? 1 : n.length : 0;
|
|
44
|
+
}, c.prototype.emit = function(e, t, n, i, a, o) {
|
|
45
|
+
var s = r ? r + e : e;
|
|
46
|
+
if (!this._events[s]) return !1;
|
|
47
|
+
var c = this._events[s], l = arguments.length, u, d;
|
|
48
|
+
if (c.fn) {
|
|
49
|
+
switch (c.once && this.removeListener(e, c.fn, void 0, !0), l) {
|
|
50
|
+
case 1: return c.fn.call(c.context), !0;
|
|
51
|
+
case 2: return c.fn.call(c.context, t), !0;
|
|
52
|
+
case 3: return c.fn.call(c.context, t, n), !0;
|
|
53
|
+
case 4: return c.fn.call(c.context, t, n, i), !0;
|
|
54
|
+
case 5: return c.fn.call(c.context, t, n, i, a), !0;
|
|
55
|
+
case 6: return c.fn.call(c.context, t, n, i, a, o), !0;
|
|
56
|
+
}
|
|
57
|
+
for (d = 1, u = Array(l - 1); d < l; d++) u[d - 1] = arguments[d];
|
|
58
|
+
c.fn.apply(c.context, u);
|
|
59
|
+
} else {
|
|
60
|
+
var f = c.length, p;
|
|
61
|
+
for (d = 0; d < f; d++) switch (c[d].once && this.removeListener(e, c[d].fn, void 0, !0), l) {
|
|
62
|
+
case 1:
|
|
63
|
+
c[d].fn.call(c[d].context);
|
|
64
|
+
break;
|
|
65
|
+
case 2:
|
|
66
|
+
c[d].fn.call(c[d].context, t);
|
|
67
|
+
break;
|
|
68
|
+
case 3:
|
|
69
|
+
c[d].fn.call(c[d].context, t, n);
|
|
70
|
+
break;
|
|
71
|
+
case 4:
|
|
72
|
+
c[d].fn.call(c[d].context, t, n, i);
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
if (!u) for (p = 1, u = Array(l - 1); p < l; p++) u[p - 1] = arguments[p];
|
|
76
|
+
c[d].fn.apply(c[d].context, u);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return !0;
|
|
80
|
+
}, c.prototype.on = function(e, t, n) {
|
|
81
|
+
return o(this, e, t, n, !1);
|
|
82
|
+
}, c.prototype.once = function(e, t, n) {
|
|
83
|
+
return o(this, e, t, n, !0);
|
|
84
|
+
}, c.prototype.removeListener = function(e, t, n, i) {
|
|
85
|
+
var a = r ? r + e : e;
|
|
86
|
+
if (!this._events[a]) return this;
|
|
87
|
+
if (!t) return s(this, a), this;
|
|
88
|
+
var o = this._events[a];
|
|
89
|
+
if (o.fn) o.fn === t && (!i || o.once) && (!n || o.context === n) && s(this, a);
|
|
90
|
+
else {
|
|
91
|
+
for (var c = 0, l = [], u = o.length; c < u; c++) (o[c].fn !== t || i && !o[c].once || n && o[c].context !== n) && l.push(o[c]);
|
|
92
|
+
l.length ? this._events[a] = l.length === 1 ? l[0] : l : s(this, a);
|
|
93
|
+
}
|
|
94
|
+
return this;
|
|
95
|
+
}, c.prototype.removeAllListeners = function(e) {
|
|
96
|
+
var t;
|
|
97
|
+
return e ? (t = r ? r + e : e, this._events[t] && s(this, t)) : (this._events = new i(), this._eventsCount = 0), this;
|
|
98
|
+
}, c.prototype.off = c.prototype.removeListener, c.prototype.addListener = c.prototype.on, c.prefixed = r, c.EventEmitter = c, t !== void 0 && (t.exports = c);
|
|
99
|
+
})))(), 1), f = class {
|
|
5
100
|
heap;
|
|
6
101
|
pool;
|
|
7
|
-
constructor(
|
|
8
|
-
this.heap =
|
|
102
|
+
constructor(t, n, r) {
|
|
103
|
+
this.heap = t, this.pool = new e(t, {
|
|
9
104
|
type: n,
|
|
10
105
|
dataLength: r
|
|
11
106
|
});
|
|
@@ -35,7 +130,7 @@ var i = class {
|
|
|
35
130
|
clear() {
|
|
36
131
|
this.pool.clear();
|
|
37
132
|
}
|
|
38
|
-
},
|
|
133
|
+
}, p = class {
|
|
39
134
|
world;
|
|
40
135
|
name;
|
|
41
136
|
currentDelta = 0;
|
|
@@ -59,7 +154,7 @@ var i = class {
|
|
|
59
154
|
return !0;
|
|
60
155
|
}
|
|
61
156
|
destroy() {}
|
|
62
|
-
},
|
|
157
|
+
}, m = class extends p {
|
|
63
158
|
remainingInstancesToRun = [];
|
|
64
159
|
remainingInstancesStartTime = null;
|
|
65
160
|
iterationsPerCheck;
|
|
@@ -87,7 +182,7 @@ var i = class {
|
|
|
87
182
|
this.remainingInstancesToRun = [], this.remainingInstancesStartTime = null;
|
|
88
183
|
}
|
|
89
184
|
beforeRunIterables() {}
|
|
90
|
-
},
|
|
185
|
+
}, h = class extends m {
|
|
91
186
|
entities = [];
|
|
92
187
|
options;
|
|
93
188
|
constructor(e, t = { name: "EntitySystem" }) {
|
|
@@ -121,12 +216,12 @@ var i = class {
|
|
|
121
216
|
shouldRun() {
|
|
122
217
|
return this.entities.length > 0;
|
|
123
218
|
}
|
|
124
|
-
},
|
|
219
|
+
}, g = class {
|
|
125
220
|
onmessage(e, t = []) {}
|
|
126
221
|
};
|
|
127
222
|
//#endregion
|
|
128
223
|
//#region src/systems/workers/apply-query-delta.ts
|
|
129
|
-
function
|
|
224
|
+
function _(e, t) {
|
|
130
225
|
if (t.removed.length) {
|
|
131
226
|
let n = new Set(t.removed);
|
|
132
227
|
e = e.filter((e) => !n.has(e.entityId));
|
|
@@ -143,7 +238,7 @@ function l(e, t) {
|
|
|
143
238
|
}
|
|
144
239
|
//#endregion
|
|
145
240
|
//#region src/systems/workers/component-web-worker.ts
|
|
146
|
-
var
|
|
241
|
+
var v = class extends g {
|
|
147
242
|
updateFunction;
|
|
148
243
|
entities = [];
|
|
149
244
|
queryEntities = {};
|
|
@@ -154,10 +249,10 @@ var u = class extends c {
|
|
|
154
249
|
if (e.type === "init") this.onMessageTyped({ type: "loaded" });
|
|
155
250
|
else if (e.type === "run") {
|
|
156
251
|
let t = [], n = [];
|
|
157
|
-
this.entities =
|
|
252
|
+
this.entities = _(this.entities, e.entities);
|
|
158
253
|
let r = {};
|
|
159
254
|
Object.entries(e.queries).forEach(([e, t]) => {
|
|
160
|
-
let n =
|
|
255
|
+
let n = _(this.queryEntities[e] ?? [], t);
|
|
161
256
|
this.queryEntities[e] = n, r[e] = n;
|
|
162
257
|
});
|
|
163
258
|
let i = {
|
|
@@ -197,7 +292,7 @@ var u = class extends c {
|
|
|
197
292
|
onMessageTyped(e) {
|
|
198
293
|
this.onmessage({ data: e });
|
|
199
294
|
}
|
|
200
|
-
},
|
|
295
|
+
}, y = "___main", b = class extends p {
|
|
201
296
|
entities = [];
|
|
202
297
|
options;
|
|
203
298
|
worker;
|
|
@@ -216,7 +311,7 @@ var u = class extends c {
|
|
|
216
311
|
this.removeEntity(e);
|
|
217
312
|
}), e.entities.forEach((e) => {
|
|
218
313
|
this.checkAddEntity(e);
|
|
219
|
-
}), !t.forceMainThread && globalThis.Worker !== void 0 && globalThis.SharedArrayBuffer !== void 0 ? (this.worker = t.getWorker(), this.isWorkerThread = !0) : (this.worker = new
|
|
314
|
+
}), !t.forceMainThread && globalThis.Worker !== void 0 && globalThis.SharedArrayBuffer !== void 0 ? (this.worker = t.getWorker(), this.isWorkerThread = !0) : (this.worker = new v(t.updateFunction), this.isWorkerThread = !1), this.initWorker();
|
|
220
315
|
}
|
|
221
316
|
initWorker() {
|
|
222
317
|
this.worker.onmessage = (e) => {
|
|
@@ -251,7 +346,7 @@ var u = class extends c {
|
|
|
251
346
|
elapsedTime: e
|
|
252
347
|
};
|
|
253
348
|
this.addDataToWorld?.(t), this.isRunning = !0;
|
|
254
|
-
let n = this.buildQueryDelta(
|
|
349
|
+
let n = this.buildQueryDelta(y, this.options), r = {};
|
|
255
350
|
Object.entries(this.options.queries ?? {}).forEach(([e, t]) => {
|
|
256
351
|
r[e] = this.buildQueryDelta(e, t);
|
|
257
352
|
});
|
|
@@ -314,13 +409,13 @@ var u = class extends c {
|
|
|
314
409
|
}
|
|
315
410
|
checkAddEntity(e) {
|
|
316
411
|
let t = this.matchesQuery(e, this.options);
|
|
317
|
-
return this.updateEntityList(
|
|
412
|
+
return this.updateEntityList(y, this.entities, e, t), Object.entries(this.options.queries ?? {}).forEach(([t, n]) => {
|
|
318
413
|
let r = this.queryEntities[t] ?? (this.queryEntities[t] = []);
|
|
319
414
|
this.updateEntityList(t, r, e, this.matchesQuery(e, n));
|
|
320
415
|
}), t;
|
|
321
416
|
}
|
|
322
417
|
removeEntity(e) {
|
|
323
|
-
this.updateEntityList(
|
|
418
|
+
this.updateEntityList(y, this.entities, e, !1), Object.entries(this.queryEntities).forEach(([t, n]) => {
|
|
324
419
|
this.updateEntityList(t, n, e, !1);
|
|
325
420
|
});
|
|
326
421
|
}
|
|
@@ -330,7 +425,7 @@ var u = class extends c {
|
|
|
330
425
|
destroy() {
|
|
331
426
|
"terminate" in this.worker && this.worker.terminate();
|
|
332
427
|
}
|
|
333
|
-
},
|
|
428
|
+
}, x = 0, S = 1, C = {
|
|
334
429
|
type: Uint32Array,
|
|
335
430
|
size: 2,
|
|
336
431
|
loadProperties: ["type", "isStatic"],
|
|
@@ -357,14 +452,14 @@ var u = class extends c {
|
|
|
357
452
|
let t = {};
|
|
358
453
|
return e.type && (t.type = e.type), e.dead && (t.dead = !0), t;
|
|
359
454
|
}
|
|
360
|
-
},
|
|
455
|
+
}, w = class e extends d.default {
|
|
361
456
|
static eidCounter = 1;
|
|
362
457
|
eid;
|
|
363
458
|
config;
|
|
364
459
|
world;
|
|
365
460
|
components = {};
|
|
366
|
-
constructor(
|
|
367
|
-
super(), this.world =
|
|
461
|
+
constructor(t, n) {
|
|
462
|
+
super(), this.world = t, this.eid = e.eidCounter++, this.loadComponent("entity", n ?? {}, !1), n && this.load(n);
|
|
368
463
|
}
|
|
369
464
|
loadComponent(e, t, n = !0) {
|
|
370
465
|
let r = this.world.registry[e], i = r.memoryComponent, a = r.load(this, i, t);
|
|
@@ -420,7 +515,7 @@ var u = class extends c {
|
|
|
420
515
|
i.loadInFinishLoading && i.loadProperties.some((e) => e in t) && this.loadComponent(r, e, !1);
|
|
421
516
|
}
|
|
422
517
|
}
|
|
423
|
-
},
|
|
518
|
+
}, T = class {
|
|
424
519
|
world;
|
|
425
520
|
configs;
|
|
426
521
|
constructor(e = {}) {
|
|
@@ -441,9 +536,9 @@ var u = class extends c {
|
|
|
441
536
|
return this.world.addEntity(n, t);
|
|
442
537
|
}
|
|
443
538
|
createEntity(e) {
|
|
444
|
-
return new
|
|
539
|
+
return new w(this.world, e);
|
|
445
540
|
}
|
|
446
|
-
},
|
|
541
|
+
}, E = t, D = class extends d.default {
|
|
447
542
|
heap;
|
|
448
543
|
registry;
|
|
449
544
|
factory;
|
|
@@ -456,19 +551,19 @@ var u = class extends c {
|
|
|
456
551
|
paused = !1;
|
|
457
552
|
destroyed = !1;
|
|
458
553
|
constructor(e, t = {}) {
|
|
459
|
-
super(), this.heap = new
|
|
460
|
-
let
|
|
554
|
+
super(), this.heap = new n({ bufferSize: t.heapSize ?? E });
|
|
555
|
+
let r = {
|
|
461
556
|
...e,
|
|
462
|
-
entity:
|
|
463
|
-
},
|
|
464
|
-
for (let e of Object.keys(
|
|
465
|
-
let t =
|
|
466
|
-
|
|
557
|
+
entity: C
|
|
558
|
+
}, i = {};
|
|
559
|
+
for (let e of Object.keys(r)) {
|
|
560
|
+
let t = r[e];
|
|
561
|
+
i[e] = {
|
|
467
562
|
...t,
|
|
468
|
-
memoryComponent: new
|
|
563
|
+
memoryComponent: new f(this.heap, t.type, t.size)
|
|
469
564
|
};
|
|
470
565
|
}
|
|
471
|
-
this.registry =
|
|
566
|
+
this.registry = i, this.factory = t.factory ?? new T(), this.factory.world = this;
|
|
472
567
|
}
|
|
473
568
|
async init() {
|
|
474
569
|
await Promise.all(this.systems.map((e) => e.init()).filter((e) => e instanceof Promise));
|
|
@@ -542,12 +637,12 @@ var u = class extends c {
|
|
|
542
637
|
}
|
|
543
638
|
addEntityToComponentSystem(e, t) {
|
|
544
639
|
this.systems.forEach((n) => {
|
|
545
|
-
(n instanceof
|
|
640
|
+
(n instanceof h && n.options.components?.includes(t) || n instanceof b && this.componentAffectsComponentSystem(n, t)) && n.checkAddEntity(e);
|
|
546
641
|
});
|
|
547
642
|
}
|
|
548
643
|
removeEntityFromComponentSystem(e, t) {
|
|
549
644
|
this.systems.forEach((n) => {
|
|
550
|
-
n instanceof
|
|
645
|
+
n instanceof h && n.options.components?.includes(t) ? n.removeEntity(e) : n instanceof b && this.componentAffectsComponentSystem(n, t) && n.checkAddEntity(e);
|
|
551
646
|
});
|
|
552
647
|
}
|
|
553
648
|
componentAffectsComponentSystem(e, t) {
|
|
@@ -562,36 +657,36 @@ var u = class extends c {
|
|
|
562
657
|
};
|
|
563
658
|
//#endregion
|
|
564
659
|
//#region src/actions/kill-entity.ts
|
|
565
|
-
function
|
|
660
|
+
function O(e) {
|
|
566
661
|
e.components.entity.dead = !0, e.emit("death");
|
|
567
662
|
}
|
|
568
663
|
//#endregion
|
|
569
664
|
//#region src/actions/kill-entity-worker.ts
|
|
570
|
-
function
|
|
665
|
+
function k(e, t, n) {
|
|
571
666
|
let r = t.entity;
|
|
572
667
|
r && (r[0] = 1), n.entityDied(e);
|
|
573
668
|
}
|
|
574
669
|
//#endregion
|
|
575
670
|
//#region src/actions/create-entity-worker.ts
|
|
576
|
-
function
|
|
671
|
+
function A(e, t) {
|
|
577
672
|
t.createEntity(e);
|
|
578
673
|
}
|
|
579
674
|
//#endregion
|
|
580
675
|
//#region src/systems/workers/create-component-worker.ts
|
|
581
|
-
function
|
|
676
|
+
function j(e, t) {
|
|
582
677
|
let n = [], r = {};
|
|
583
678
|
e.onmessage = function(i) {
|
|
584
679
|
let a = i.data;
|
|
585
|
-
if (a.type === "init")
|
|
680
|
+
if (a.type === "init") M(e, { type: "loaded" });
|
|
586
681
|
else if (a.type === "run") {
|
|
587
682
|
let i = performance.now(), o = [], s = [];
|
|
588
|
-
n =
|
|
683
|
+
n = _(n, a.entities);
|
|
589
684
|
let c = {};
|
|
590
685
|
Object.entries(a.queries).forEach(([e, t]) => {
|
|
591
|
-
let n =
|
|
686
|
+
let n = _(r[e] ?? [], t);
|
|
592
687
|
r[e] = n, c[e] = n;
|
|
593
688
|
});
|
|
594
|
-
let
|
|
689
|
+
let l = {
|
|
595
690
|
entityComponentChanged(e, t, n, r) {
|
|
596
691
|
o.push({
|
|
597
692
|
entityId: e,
|
|
@@ -614,11 +709,11 @@ function C(e, t) {
|
|
|
614
709
|
s.push(e);
|
|
615
710
|
}
|
|
616
711
|
};
|
|
617
|
-
t.preRun && t.preRun(a.world, n, c,
|
|
618
|
-
t(a.world, e.entityId, e.components, c,
|
|
712
|
+
t.preRun && t.preRun(a.world, n, c, l), n.forEach((e) => {
|
|
713
|
+
t(a.world, e.entityId, e.components, c, l);
|
|
619
714
|
}), t.entityRemoved && a.entities.removed.forEach((e) => {
|
|
620
|
-
t.entityRemoved(a.world, e,
|
|
621
|
-
}),
|
|
715
|
+
t.entityRemoved(a.world, e, l);
|
|
716
|
+
}), M(e, {
|
|
622
717
|
type: "run-complete",
|
|
623
718
|
runTime: performance.now() - i,
|
|
624
719
|
events: o,
|
|
@@ -627,10 +722,10 @@ function C(e, t) {
|
|
|
627
722
|
}
|
|
628
723
|
};
|
|
629
724
|
}
|
|
630
|
-
function
|
|
725
|
+
function M(e, t) {
|
|
631
726
|
e.postMessage(t);
|
|
632
727
|
}
|
|
633
728
|
//#endregion
|
|
634
|
-
export {
|
|
729
|
+
export { w as BaseEntity, D as BaseWorld, b as ComponentSystem, v as ComponentWebWorker, x as DEAD_INDEX, T as EntityFactory, h as EntitySystem, m as IterableSystem, f as MemoryComponent, S as STATIC_INDEX, p as System, g as WebWorker, j as createComponentWorker, A as createEntityWorker, C as entityDefinition, O as killEntity, k as killEntityWorker };
|
|
635
730
|
|
|
636
731
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/memory-component.ts","../src/systems/system.ts","../src/systems/iterable-system.ts","../src/systems/entity-system.ts","../src/systems/workers/web-worker.ts","../src/systems/workers/apply-query-delta.ts","../src/systems/workers/component-web-worker.ts","../src/systems/component-system.ts","../src/entity-component.ts","../src/entity.ts","../src/entity-factory.ts","../src/world.ts","../src/actions/kill-entity.ts","../src/actions/kill-entity-worker.ts","../src/actions/create-entity-worker.ts","../src/systems/workers/create-component-worker.ts"],"sourcesContent":["import { LocalPool, type MemoryHeap, type TypedArrayConstructor } from '@daneren2005/shared-memory-objects';\n\n// The typed arrays a MemoryComponent can be backed by. Kept narrower than the package's TypedArray\n// union on purpose since these are the only types we allocate blocks of.\nexport type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;\n\n// A pool of same sized blocks living inside a shared MemoryHeap. Each component instance owns one\n// block (referenced by its index) so component data can be shared with worker threads.\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: LocalPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number) {\n\t\tthis.heap = heap;\n\t\tthis.pool = new LocalPool(heap, {\n\t\t\ttype,\n\t\t\tdataLength,\n\t\t});\n\t}\n\n\tget length() {\n\t\treturn this.pool.length;\n\t}\n\tget rawLength() {\n\t\treturn this.pool.bufferLength;\n\t}\n\n\tcreate(values: Array<number>): number {\n\t\treturn this.pool.push(values);\n\t}\n\n\tgetBlock(index: number): T {\n\t\treturn this.pool.at(index);\n\t}\n\tget(index: number, dataIndex: number): number {\n\t\treturn this.pool.get(index, dataIndex);\n\t}\n\tset(index: number, dataIndex: number, value: number) {\n\t\tlet array = this.pool.at(index);\n\t\tarray[dataIndex] = value;\n\t}\n\n\tdelete(index: number) {\n\t\tthis.pool.deleteIndex(index);\n\t}\n\tclear() {\n\t\tthis.pool.clear();\n\t}\n}\n","import type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\n\n// Base system: runs on an optional fixed timestep (deltaBetweenRuns) and is driven by BaseWorld#update.\n// Systems only care about the component map `C`, not the World's registry (`R`) or config (`Cfg`), so they\n// reference the World through the widened `ComponentDefinitionMap` and let `Cfg` default.\nexport default abstract class System<C extends ComponentMap = ComponentMap> {\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\tthis.name = options.name;\n\t\tthis.world = world;\n\n\t\tthis.deltaBetweenRuns = options.deltaBetweenRuns ?? 0;\n\t\tthis.firstRun = options.firstRun !== undefined ? options.firstRun : false;\n\t}\n\n\tinit(): void | Promise<void> {}\n\n\tclear() {\n\t\tthis.currentDelta = 0;\n\t}\n\tfinishLoading() {}\n\n\tupdate(elapsedTime: number): boolean {\n\t\tthis.currentDelta += elapsedTime;\n\n\t\tif(this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {\n\t\t\tlet leftOverDelta = 0;\n\t\t\tif(this.deltaBetweenRuns > 0) {\n\t\t\t\t// Without this if we take 100ms to run (ie: IterableSystem across multiple frames) then we will end up\n\t\t\t\t// actually running this in 300ms total instead of again in 100ms for a total of 200ms\n\t\t\t\t// With firstRun this ends up calling run(0) the first time - this makes it so things like events are\n\t\t\t\t// will trigger on the second instead of triggering a 1 second timer at 1.0166 seconds\n\t\t\t\tleftOverDelta = this.currentDelta % this.deltaBetweenRuns;\n\t\t\t}\n\n\t\t\tthis.run(this.currentDelta - leftOverDelta);\n\t\t\tthis.currentDelta = leftOverDelta;\n\t\t\tthis.firstRun = false;\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tabstract run(elapsedTime: number): void;\n\n\tshouldRun(): boolean {\n\t\treturn true;\n\t}\n\n\tdestroy() {}\n}\n\nexport interface SystemConfig {\n\tname: string\n\tdeltaBetweenRuns?: number\n\t// Defaults to false\n\tfirstRun?: boolean\n}\n","import type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\nimport System, { type SystemConfig } from './system';\n\n// A system that iterates a list of instances, spreading the work across multiple frames if a single\n// pass would exceed maxMsPerFrame.\nexport default abstract class IterableSystem<C extends ComponentMap, T> extends System<C> {\n\tremainingInstancesToRun: Array<T> = [];\n\tremainingInstancesStartTime: number | null = null;\n\titerationsPerCheck: number;\n\tmaxMsPerFrame: number;\n\n\tconstructor(world: BaseWorld<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 that own a given set of components on the main thread. Entities are added\n// and removed automatically as the world emits entity-added / entity-removed / component changes.\nexport default abstract class EntitySystem<C extends ComponentMap, T extends BaseEntity<C> = BaseEntity<C>> extends IterableSystem<C, T> {\n\tentities: Array<T> = [];\n\toptions: EntitySystemConfig<C>;\n\n\tconstructor(world: BaseWorld<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\treturn this.entities.filter(entity => !entity.components.entity.dead);\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.indexOf(entity as T) !== -1;\n\t}\n\tabstract updateEntity(entity: T, elapsedTime: number): void;\n\n\tcheckAddEntity(entity: BaseEntity<C>): boolean {\n\t\tif(this.options.components && this.options.components.filter(component => !!entity.components[component]).length !== this.options.components.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(this.filterEntity(entity)) {\n\t\t\tthis.entities.push(entity as T);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tremoveEntity(entity: BaseEntity<C>) {\n\t\tlet index = this.entities.indexOf(entity as T);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t}\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.length > 0;\n\t}\n}\n\nexport interface EntitySystemConfig<C extends ComponentMap> extends IterableSystemConfig {\n\tcomponents?: Array<keyof C>\n\tupdateEntityOnAdd?: boolean\n}\n","// Minimal Worker-like base used for the main-thread fallback when real Web Workers / SharedArrayBuffer\n// are unavailable. Params are intentionally loose since this is the (serialization) boundary that\n// mirrors the DOM Worker interface.\nexport default abstract class WebWorker {\n\tabstract postMessage(message: any): void | Promise<void>;\n\tonmessage(message: any, transferrables: Array<any> = []): void {\n\n\t}\n}\n","import type { EntityUpdateComponents, QueryDelta, UpdateEntityConfigObject } from '../component-system';\n\n// A worker keeps one persistent list per query and applies the delta each run carries: drop the entities that\n// left, then upsert the ones that joined (or whose component blocks changed). Because the main thread only\n// sends changes, a steady-state run - where membership is unchanged - carries empty arrays and this returns the\n// existing list untouched with no allocation, which is the whole point of the delta protocol: we stop\n// re-transmitting (and re-cloning) every entity id every single frame.\n//\n// The list is returned (rather than mutated in place) because removals rebuild it via filter; callers must store\n// the returned reference back as their persistent list.\nexport function applyQueryDelta<T extends EntityUpdateComponents>(\n\tlist: Array<UpdateEntityConfigObject<T>>,\n\tdelta: QueryDelta<T>,\n): Array<UpdateEntityConfigObject<T>> {\n\tif(delta.removed.length) {\n\t\tconst removedSet = new Set(delta.removed);\n\t\tlist = list.filter(entry => !removedSet.has(entry.entityId));\n\t}\n\n\tif(delta.added.length) {\n\t\t// Map existing members so a re-added entity (its component set changed) replaces its entry in place\n\t\t// instead of being duplicated; genuinely new entities are appended.\n\t\tconst indexByEid = new Map<number, number>();\n\t\tlist.forEach((entry, index) => indexByEid.set(entry.entityId, index));\n\n\t\tfor(let entity of delta.added) {\n\t\t\tconst existing = indexByEid.get(entity.entityId);\n\t\t\tif(existing !== undefined) {\n\t\t\t\tlist[existing] = entity;\n\t\t\t} else {\n\t\t\t\tindexByEid.set(entity.entityId, list.length);\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn list;\n}\n","import WebWorker from './web-worker';\nimport { applyQueryDelta } from './apply-query-delta';\nimport type ComponentWorkerMessage 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 when real Web Workers /\n// SharedArrayBuffer are unavailable. It runs in-process but still keeps persistent per-query lists and applies\n// the same membership deltas the real worker does, so both backends stay behavior-identical.\nexport default class ComponentWebWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> extends WebWorker {\n\tprivate updateFunction: EntityUpdateFunction<C, T, W>;\n\tprivate entities: Array<UpdateEntityConfigObject<T>> = [];\n\tprivate queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\n\tconstructor(updateFunction: EntityUpdateFunction<C, T, W>) {\n\t\tsuper();\n\t\tthis.updateFunction = updateFunction;\n\t}\n\n\tpostMessage(message: ComponentWorkerMessage<W>): void {\n\t\tif(message.type === 'init') {\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\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\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\tthis.onMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime: 0,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t});\n\t\t}\n\t}\n\n\tonMessageTyped(message: ComponentWorkerMessage<W>) {\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, ideally on a\n// separate thread. When Web Workers + SharedArrayBuffer are available the work happens on `getWorker()`;\n// otherwise it falls back to running synchronously on the main thread via ComponentWebWorker.\n//\n// This is deliberately free of any game concepts (no factions, fog of war, position, etc). Games\n// inject whatever extra per-run data they need through `addDataToWorld`.\nexport default abstract class ComponentSystem<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n> extends System<C> {\n\tentities: Array<BaseEntity<C>> = [];\n\toptions: ComponentSystemConfig<C, T, W>;\n\n\tworker: Worker | ComponentWebWorker<C, T, W>;\n\tisWorkerThread: boolean;\n\n\tprivate loaded = false;\n\tprivate loadingPromise: { promise: Promise<void>, resolve: (value: void | PromiseLike<void>) => void } | null = null;\n\tprivate isRunning = false;\n\tprivate queryEntities: { [key: string]: Array<BaseEntity<C>> } = {};\n\t// Per-query membership changes accumulated since the last run(). Each run() flushes these to the worker as a\n\t// delta - added entities carry their component blocks, removed carry just their eid - so a steady-state run\n\t// (unchanged membership) sends empty arrays instead of re-transmitting every entity id every single frame.\n\t// The worker keeps its own persistent list and applies these deltas to it (see applyQueryDelta).\n\tprivate queryDeltas: { [key: string]: MembershipDelta<C> } = {};\n\n\t// Optional hook for subclasses to attach extra data to the world object sent to the worker. Subclasses\n\t// declare the concrete shape through `W` and fill in its fields here.\n\taddDataToWorld?(world: W): void;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: ComponentSystemConfig<C, T, W>) {\n\t\tsuper(world, options);\n\t\tthis.options = options;\n\t\tObject.keys(this.options.queries ?? {}).forEach(queryName => {\n\t\t\tthis.queryEntities[queryName] = [];\n\t\t});\n\n\t\tworld.on('entity-added', (entity: BaseEntity<C>) => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t\tworld.on('entity-removed', (entity: BaseEntity<C>) => {\n\t\t\tthis.removeEntity(entity);\n\t\t});\n\n\t\tworld.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\n\t\tif(!options.forceMainThread && typeof globalThis.Worker !== 'undefined' && typeof globalThis.SharedArrayBuffer !== 'undefined') {\n\t\t\tthis.worker = options.getWorker();\n\t\t\tthis.isWorkerThread = true;\n\t\t} else {\n\t\t\tthis.worker = new ComponentWebWorker(options.updateFunction);\n\t\t\tthis.isWorkerThread = false;\n\t\t}\n\n\t\tthis.initWorker();\n\t}\n\n\tprivate initWorker() {\n\t\tthis.worker.onmessage = (e: MessageEvent) => {\n\t\t\tlet message = e.data as ComponentWorkerMessage;\n\t\t\tif(message.type === 'loaded') {\n\t\t\t\tthis.loaded = true;\n\t\t\t\tif(this.loadingPromise) {\n\t\t\t\t\tthis.loadingPromise.resolve();\n\t\t\t\t\tthis.loadingPromise = null;\n\t\t\t\t}\n\t\t\t} else if(message.type === 'run-complete') {\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tif(this.isWorkerThread) {\n\t\t\t\t\tthis.world.emit(`system-${this.name}-worker-finished`, message.runTime);\n\t\t\t\t}\n\n\t\t\t\tmessage.events.forEach(event => {\n\t\t\t\t\t// A system can report events (deaths, component changes) for entities it only knows through a\n\t\t\t\t\t// sub-query - e.g. a collision system that kills a station it found in a spatial query but that\n\t\t\t\t\t// isn't in its main query. Look the entity up on the world so those still route even when the\n\t\t\t\t\t// entity was never part of this system's main query cache.\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(`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// Fulfill any creation requests after deaths, so an entity created this run isn't immediately removed.\n\t\t\t\t// loadEntity runs the full factory expansion + finishLoading and emits `entity-added`, so every system\n\t\t\t\t// (including this one) picks the new entity up on the next run.\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\tif(this.isWorkerThread) {\n\t\t\t\t\tthis.world.emit(`system-${this.name}-worker-events-finished`, message.runTime);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage = {\n\t\t\ttype: 'init',\n\t\t};\n\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tinit(): Promise<void> | void {\n\t\tif(this.loaded) {\n\t\t\treturn;\n\t\t} else if(this.loadingPromise) {\n\t\t\treturn this.loadingPromise.promise;\n\t\t}\n\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\tthis.loadingPromise = {\n\t\t\tpromise,\n\t\t\tresolve,\n\t\t};\n\t\treturn promise;\n\t}\n\n\tupdate(elapsedTime: number): boolean {\n\t\t// Only run worker if the last run completed already\n\t\tif(this.isRunning) {\n\t\t\tthis.currentDelta += elapsedTime;\n\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn super.update(elapsedTime);\n\t\t}\n\t}\n\trun(elapsedTime: number): void {\n\t\t// gameTime + elapsedTime are the only fields the base guarantees; addDataToWorld fills in the rest of `W`,\n\t\t// so the literal is built as the base shape and widened to W for that hook to complete.\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\tworld,\n\t\t\tentities,\n\t\t\tqueries,\n\t\t};\n\t\tthis.worker.postMessage(message);\n\t}\n\n\t// Flushes the pending membership changes for a query into the delta the worker applies to its persistent\n\t// list. Added entities are resolved to their shared-memory component blocks here (the only per-frame cost\n\t// left, and only for entities that actually joined/changed); removed entities are sent as bare eids. The\n\t// buffers are reset so the next run only carries what changed since this one.\n\tprivate buildQueryDelta(queryName: string, query: ComponentSystemQuery<C>): QueryDelta<T> {\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tconst added = delta.added.map(entity => ({\n\t\t\tentityId: entity.eid,\n\t\t\tcomponents: this.buildComponents(entity, query),\n\t\t}));\n\t\tconst removed = delta.removed;\n\t\tthis.queryDeltas[queryName] = { added: [], removed: [] };\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.indexOf(entity) !== -1;\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: [], removed: [] };\n\t\t}\n\n\t\treturn delta;\n\t}\n\t// Records that an entity now belongs to a query, so the next run() sends its (possibly changed) component\n\t// blocks. An entity queued for removal this same frame is un-queued instead: the worker never learned it\n\t// left, so the net effect is a re-send of fresh components rather than a remove+add churn.\n\tprivate markAdded(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tconst removedIndex = delta.removed.indexOf(entity.eid);\n\t\tif(removedIndex !== -1) {\n\t\t\tdelta.removed.splice(removedIndex, 1);\n\t\t}\n\t\tif(delta.added.indexOf(entity) === -1) {\n\t\t\tdelta.added.push(entity);\n\t\t}\n\t}\n\t// Records that an entity left a query. If it was only queued to be added this same frame (never sent to the\n\t// worker), we just drop the pending add - the worker never knew about it, so there is nothing to remove.\n\tprivate markRemoved(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tconst addedIndex = delta.added.indexOf(entity);\n\t\tif(addedIndex !== -1) {\n\t\t\tdelta.added.splice(addedIndex, 1);\n\t\t\treturn;\n\t\t}\n\t\tif(delta.removed.indexOf(entity.eid) === -1) {\n\t\t\tdelta.removed.push(entity.eid);\n\t\t}\n\t}\n\tprivate updateEntityList(queryName: string, list: Array<BaseEntity<C>>, entity: BaseEntity<C>, shouldInclude: boolean) {\n\t\tconst index = list.indexOf(entity);\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tif(shouldInclude) {\n\t\t\tif(index === -1) {\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t\t// Always (re)queue the component blocks: the entity either just joined or a relevant component was\n\t\t\t// added/removed, so the blocks the worker holds for it may be stale.\n\t\t\tthis.markAdded(delta, entity);\n\t\t} else if(index !== -1) {\n\t\t\tlist.splice(index, 1);\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] = []);\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.length > 0;\n\t}\n\n\tdestroy() {\n\t\tif('terminate' in this.worker) {\n\t\t\tthis.worker.terminate();\n\t\t}\n\t}\n}\n\nexport type EntityUpdateComponents<C extends ComponentMap = ComponentMap> = { [K in keyof C]?: ComponentTypedArray };\nexport type EntityQueryComponents<C extends ComponentMap = ComponentMap> = { [key: string]: Array<{ entityId: number, components: EntityUpdateComponents<C> }> };\ntype EntityUpdateFunctionImpl<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentityId: number,\n\tcomponents: T,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\n// `T` is required (no default) so every update function must spell out exactly which components it operates on\n// and their concrete typed arrays, rather than falling back to the full component list. `W` is the concrete\n// per-run world shape the owning system builds in addDataToWorld; it defaults to the bare ComponentSystemWorld.\nexport type EntityUpdateFunction<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> = EntityUpdateFunctionImpl<C, T, W> & {\n\tpreRun?: EntityUpdatePreRunFunction<C, T, W>\n\tentityRemoved?: EntityRemovedFunction<C, W>\n};\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\n// The membership changes for a single query since the last run, in the shape sent to the worker: entities that\n// joined (or whose component set changed) with their resolved component blocks, and the eids of entities that\n// left. Empty on a steady-state run, which is what keeps the per-frame postMessage small.\nexport interface QueryDelta<T extends EntityUpdateComponents = EntityUpdateComponents> {\n\tadded: Array<UpdateEntityConfigObject<T>>\n\tremoved: Array<number>\n}\n// The main thread's pre-serialization form of a QueryDelta: it holds the live entities (so their component\n// blocks can be resolved lazily at run time), whereas QueryDelta holds the resolved blocks that cross the wire.\ninterface MembershipDelta<C extends ComponentMap> {\n\tadded: Array<BaseEntity<C>>\n\tremoved: Array<number>\n}\n\n// Base per-run world data. gameTime + elapsedTime are always present; games attach anything else\n// they need via addDataToWorld, declaring the concrete shape through the `W` type parameter that\n// ComponentSystem (and its update function) are generic over.\nexport interface ComponentSystemWorld {\n\tgameTime: number\n\telapsedTime: number\n}\n// A flat entity config a worker asks the main thread to create. Kept as a plain record (not the game's `Cfg`)\n// because ComponentSystem is generic over `C`, not `Cfg`; the main thread hands it straight to world.loadEntity,\n// whose factory expands its `type` against the registered templates.\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\tentityDied(entityId: number): void\n\t// Requests that the main thread create an entity from `config` once the run completes. Unlike killing (which\n\t// flips an existing shared-memory flag in place), creation can't happen in the worker, so it is deferred to the\n\t// main thread where eid generation, allocation, and factory expansion already live.\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> extends SystemConfig, ComponentSystemQuery<C> {\n\tupdateFunction: EntityUpdateFunction<C, T, W>\n\tgetWorker: () => Worker\n\tforceMainThread?: boolean\n\n\tqueries?: { [key: string]: ComponentSystemQuery<C> }\n}\n\n// Re-exported so BaseComponent is reachable from the systems barrel if needed.\nexport type { BaseComponent };\n","import type { ComponentDefinition } from './component-definition';\n\n// The one component every entity is required to have. `dead` and `isStatic` are boolean flags stored in\n// the shared-memory block so a worker that pulls the `entity` component into its query can read them too.\n// `type` is a plain string that names the EntityFactory template this entity was built from; it lives off\n// to the side (not in shared memory), so - unlike `dead`/`isStatic` - it is NOT visible to workers.\n// Games that need a stable string id (or any other per-entity data) add their own component for it.\nexport interface EntityComponent {\n\tindex: number\n\ttype: string\n\tdead: boolean\n\tisStatic: boolean\n}\n\n// The defining config for the entity component. `type` is required - every entity is created from a factory\n// template, named by its type - while `isStatic` is an optional flag supplied up front.\nexport interface EntityComponentConfig {\n\ttype: string\n\tisStatic?: boolean\n}\n\n// Runtime-derived state plus `type`: `dead` is only meaningful once the entity is alive, and `type` is kept\n// so a save can be re-expanded through the factory. `isStatic` is intentionally absent - it comes back from\n// the type's template config, not the save.\nexport interface EntityComponentSerialization {\n\ttype?: string\n\tdead?: boolean\n}\n\nexport const DEAD_INDEX = 0;\nexport const STATIC_INDEX = 1;\n\nexport const entityDefinition: ComponentDefinition<EntityComponent, Uint32Array, EntityComponentConfig, EntityComponentSerialization> = {\n\ttype: Uint32Array,\n\tsize: 2,\n\t// The entity component is always loaded by BaseEntity's constructor, so this never actually gates\n\t// loading; it documents the defining config props and keeps it consistent with game components.\n\tloadProperties: ['type', 'isStatic'],\n\tload(entity, memory, config) {\n\t\tconst index = memory.create([config.dead ? 1 : 0, config.isStatic ? 1 : 0]);\n\t\tconst block = memory.getBlock(index);\n\n\t\treturn {\n\t\t\tindex,\n\t\t\t// Plain (non-memory) property, so it is main-thread only and not readable from workers.\n\t\t\ttype: config.type,\n\t\t\tget dead() {\n\t\t\t\treturn block[DEAD_INDEX] === 1;\n\t\t\t},\n\t\t\tset dead(value: boolean) {\n\t\t\t\tblock[DEAD_INDEX] = value ? 1 : 0;\n\t\t\t},\n\t\t\tget isStatic() {\n\t\t\t\treturn block[STATIC_INDEX] === 1;\n\t\t\t},\n\t\t\tset isStatic(value: boolean) {\n\t\t\t\tblock[STATIC_INDEX] = value ? 1 : 0;\n\t\t\t},\n\t\t};\n\t},\n\tsave(component) {\n\t\t// `type` + `dead` are serialized; `isStatic` (and the rest of the template) come back from the type's\n\t\t// config on reload, so they are deliberately left out.\n\t\tconst config: EntityComponentSerialization = {};\n\t\tif(component.type) {\n\t\t\tconfig.type = component.type;\n\t\t}\n\t\tif(component.dead) {\n\t\t\tconfig.dead = true;\n\t\t}\n\n\t\treturn config;\n\t},\n};\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { ComponentDefinitionMap, ComponentMap, RegisteredComponentRegistry } from './component-definition';\nimport type { EntityComponent } from './entity-component';\n\n// A bare entity: an eid and a bag of memory-backed components (including the required entity component).\n// `Cfg` is the flat config this entity loads from / saves to; it defaults to `any` so a bare `BaseEntity<C>`\n// stays usable, but a World derives it (via `EntityConfigOf`) so `config` and `load` are fully typed.\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\t// The World only uses its `R` param to derive `C`/`Cfg`, so entities reference it Cfg-agnostically via the\n\t// widened `ComponentDefinitionMap` - the instance shape depends on `C`/`Cfg`, not on the concrete registry.\n\tworld: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\t// The entity component is required on every entity, so it is always present (unlike the game\n\t// components, which are partial). Its `dead`/`isStatic` flags and `id` live here now.\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\t// `emitAdded` is true for runtime additions so systems can react; the loading path (constructor and\n\t// `load`) passes false, since those components are already accounted for when the entity is added.\n\tloadComponent<K extends keyof C>(name: K, config: any, emitAdded = true): C[K] {\n\t\t// registry carries the always-present entity component as an intersection; index the plain game map\n\t\t// here so the generic key stays cleanly typed as C[K].\n\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\t// The definition now owns its MemoryComponent, so the memory pool comes straight off it.\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// TS can't verify writing to a property of the generic C[K] by a keyof C[K] key, so index through a record.\n\t\t(component as unknown as Record<P, C[K][P]>)[prop] = value;\n\t\tthis.emit('component-property-updated', componentName, prop, value);\n\t}\n\t/**\n\t * NOTE: Does not emit component-property-updated!\n\t */\n\tsetComponentBulk<K extends keyof C>(componentName: K, values: Partial<C[K]>) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tObject.assign(component, values);\n\t}\n\tdeleteComponent<K extends keyof C>(componentName: K, prop: keyof C[K]) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tdelete (component as Partial<C[K]>)[prop];\n\t\tthis.emit('component-property-deleted', componentName, prop);\n\t}\n\n\tdeleteAllComponentMemory() {\n\t\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\t// Loads component data from a flat config: every registered component whose `loadProperties` appear in\n\t// the config is handed the entire config. The entity component is skipped here since the constructor\n\t// always loads it up front.\n\tload(config: Cfg) {\n\t\t// The flat config is keyed by string props; index it as a record for the `loadProperties` checks.\n\t\tconst props = config as Record<string, unknown>;\n\t\t// registry carries the intersected entity component; index the plain game map so `definition` stays typed.\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\t// Deferred components wait for finishLoading, once every entity in the batch exists.\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\t// Every component's saver returns flat props merged into one shared config, mirroring how `load`\n\t\t// hands that same flat config to each loader.\n\t\tconst config: { [key: string]: any } = {};\n\n\t\t// registry carries the intersected entity component; index the plain game map here (the entity key\n\t\t// still resolves at runtime, so its definition is picked up as well).\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\t// The merged serialization slices reconstruct a (partial) flat config, which is exactly `Cfg`.\n\t\treturn config as Cfg;\n\t}\n\t// Hook for games that need a second pass once every entity in a load batch exists. The base pass loads any\n\t// components flagged `loadInFinishLoading`, which `load` deliberately 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` name to a base (template) config. Loading an entity of a given type layers the\n// caller's config on top of that base, so shared static data (a goblin's maxHealth, say) is declared once\n// here instead of being saved on every entity - a save then only needs the `type` plus the entity's runtime\n// serialization. BaseWorld#loadEntity goes through the factory, so every load is type-expanded.\nexport default class EntityFactory<C extends ComponentMap = ComponentMap, Cfg = any> {\n\t// Set by BaseWorld when the factory is attached to it. The World only uses `R` to derive `C`/`Cfg`, so the\n\t// factory references it Cfg-agnostically through the widened `ComponentDefinitionMap`.\n\tworld!: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\t// type name -> its base config.\n\tconfigs: { [type: string]: Cfg };\n\n\tconstructor(configs: { [type: string]: Cfg } = {}) {\n\t\tthis.configs = configs;\n\t}\n\n\t// Register (or replace) the base config for an entity type.\n\tregister(type: string, config: Cfg) {\n\t\tthis.configs[type] = config;\n\t}\n\n\t// Layer a config over its type's base config. A config with no (or an unknown) `type` passes through\n\t// unchanged, so fully-specified configs can still be loaded directly.\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\t// Build a type-expanded entity and add it to the world.\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\t// Hook for games that map types to BaseEntity subclasses; override to return a subclass per config.type.\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 { MAX_BYTE_OFFSET_LENGTH, MemoryHeap } from '@daneren2005/shared-memory-objects';\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\t// Supplies the type -> base config templates; defaults to an empty factory that loads configs as-is.\n\tfactory?: EntityFactory<C, Cfg>\n}\n\n// The serialized shape of a whole world: the flat list of entity configs to (re)build plus the world clocks. A\n// game can layer its own fields on top; the World itself only needs `entities` (the same flat `Cfg` objects\n// `loadEntity` / `save` deal with) and the optional time state that `load` restores.\nexport interface WorldConfig<Cfg = any> {\n\tentities: Array<Cfg>\n\t// Simulation clock; restored so a saved world resumes at the same in-game time. Defaults to 0.\n\tgameTime?: number\n\t// Real elapsed play time; kept separate from gameTime and unaffected by timeScale. Defaults to 0.\n\tplayerTime?: number\n\t// Simulation speed multiplier. Defaults to 1.\n\ttimeScale?: number\n}\n\n// A simple wrapper around a set of entities + systems. On construction it creates one\n// MemoryComponent per entry in the component registry so entities can load/save themselves without\n// each game re-declaring loaders/savers. It has no game specific load/save/terrain/faction logic -\n// that all belongs in the game that consumes this library.\n// The World is generic over `R`, the registry of component definitions a game supplies. Both the\n// component-instance map `C` and the flat entity config `Cfg` are derived from `R` (via `ComponentsOf` /\n// `EntityConfigOf`) and default off it, so `new BaseWorld(registry)` infers `R` from its argument and every\n// entity's components and config are typed without the game declaring any composite types by hand.\nexport default class BaseWorld<\n\tR extends ComponentDefinitionMap = ComponentDefinitionMap,\n\tC extends ComponentMap = ComponentsOf<R>,\n\tCfg = EntityConfigOf<R>,\n> extends EventEmitter {\n\theap: MemoryHeap;\n\t// The entity component is always registered on top of the game's components so every entity can be\n\t// given one automatically. Each registered definition carries its own MemoryComponent, so a\n\t// component's memory pool is reachable straight from `registry[name].memoryComponent`.\n\tregistry: RegisteredComponentRegistry<C> & { entity: RegisteredComponentDefinition<EntityComponent> };\n\t// Every entity is built through the factory, which expands its `type` against the registered templates.\n\tfactory: EntityFactory<C, Cfg>;\n\n\tentities: Array<BaseEntity<C, Cfg>> = [];\n\tentitiesByEid: { [eid: number]: BaseEntity<C, Cfg> } = {};\n\tsystems: Array<System<C>> = [];\n\n\tgameTime = 0;\n\t// Real (unscaled) time the player has spent in the world. Unlike gameTime it keeps advancing while paused and\n\t// is never multiplied by timeScale.\n\tplayerTime = 0;\n\t// Multiplier applied to elapsedTime before it advances gameTime / runs systems, so a game can speed up or slow\n\t// down simulation without touching the real frame delta.\n\ttimeScale = 1;\n\t// While paused, update still accrues playerTime but skips advancing gameTime and running systems.\n\tpaused = false;\n\tdestroyed = false;\n\n\t// The game supplies its own components as `R`; the entity component is added automatically, so it must not\n\t// 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\t// Register every supplied definition (plus the always-present entity component) by attaching a freshly\n\t\t// allocated MemoryComponent to it, so the memory pool lives alongside the definition on the registry.\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\n\taddEntity(entity: BaseEntity<C, Cfg>, created = true): BaseEntity<C, Cfg> {\n\t\tthis.entities.push(entity);\n\t\tthis.entitiesByEid[entity.eid] = entity;\n\t\tentity.world = this;\n\n\t\tentity.on('component-added', (name: keyof C) => {\n\t\t\tthis.addEntityToComponentSystem(entity, name);\n\t\t});\n\t\tentity.on('component-removed', (name: keyof C) => {\n\t\t\tthis.removeEntityFromComponentSystem(entity, name);\n\t\t});\n\n\t\tif(created) {\n\t\t\tentity.finishLoading();\n\t\t\tthis.emit('entity-added', entity);\n\t\t\t// killEntity / killEntityWorker flag the entity dead and emit `death`; remove it here.\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\t// The factory expands the config's `type` against the registered templates before building the entity.\n\t\treturn this.factory.loadEntity(config, created);\n\t}\n\t// Replace the world's contents with a saved config. The existing entities (their backing memory freed) are\n\t// cleared and each system is reset via `clear()` first, then each entity is loaded with `created = false` so\n\t// no finishLoading runs mid-batch. Systems themselves are set up once ahead of time (they persist across\n\t// loads); only their per-load state is cleared here. Once every entity exists, finishLoading is called on\n\t// each - so a component that depends on other entities (e.g. a lumbermill counting nearby trees) can resolve\n\t// them, since the whole batch is guaranteed loaded by then.\n\tload(config: WorldConfig<Cfg>) {\n\t\t// Iterate over a copy since removeEntity mutates `this.entities`.\n\t\tfor(let entity of this.entities.slice()) {\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\t// killEntity / killEntityWorker flag the entity dead and emit `death`; remove it here.\n\t\t\tentity.on('death', () => {\n\t\t\t\tthis.onEntityDied(entity);\n\t\t\t});\n\t\t}\n\n\t\t// Restore the world clocks, falling back to a fresh world's defaults when the config omits them.\n\t\tthis.gameTime = config.gameTime ?? 0;\n\t\tthis.playerTime = config.playerTime ?? 0;\n\t\tthis.timeScale = config.timeScale ?? 1;\n\t}\n\tremoveEntity(entity: BaseEntity<C, Cfg>) {\n\t\tlet index = this.entities.indexOf(entity);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t\tdelete this.entitiesByEid[entity.eid];\n\t\t\tthis.emit('entity-removed', entity);\n\t\t}\n\n\t\tentity.deleteAllComponentMemory();\n\t}\n\tonEntityDied(entity: BaseEntity<C, Cfg>) {\n\t\tthis.removeEntity(entity);\n\t}\n\tgetEntityByEid(eid: number): BaseEntity<C, Cfg> | undefined {\n\t\treturn this.entitiesByEid[eid];\n\t}\n\n\taddSystem<T extends System<C>>(system: T): T {\n\t\tthis.systems.push(system);\n\t\treturn system;\n\t}\n\taddSystemIfNotExists(system: System<C>) {\n\t\tlet index = this.systems.findIndex(otherSystem => system.name === otherSystem.name);\n\t\tif(index === -1) {\n\t\t\tthis.systems.push(system);\n\t\t}\n\t}\n\tremoveSystem(name: string) {\n\t\tlet index = this.systems.findIndex(system => system.name === name);\n\t\tif(index !== -1) {\n\t\t\tthis.systems.splice(index, 1);\n\t\t}\n\t}\n\n\tupdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\t// playerTime tracks real elapsed time and keeps ticking even while paused; gameTime is the scaled,\n\t\t// pausable simulation clock the systems run against.\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// Kills an entity on the main thread: flags it dead in shared memory and emits `death` so the world and\n// any game listeners can react. BaseWorld#addEntity listens for `death` to remove the entity.\nexport default function killEntity(entity: BaseEntity): void {\n\tentity.components.entity.dead = true;\n\tentity.emit('death');\n}\n","import type { ComponentTypedArray } from '../memory-component';\nimport type { ComponentSystemCallbacks, EntityUpdateComponents } from '../systems/component-system';\nimport { DEAD_INDEX } from '../entity-component';\n\n// The worker-thread counterpart of killEntity. Called from inside a component system's update function,\n// it flags the entity dead directly in its shared-memory block and reports the death back to the main\n// thread through the callbacks so the world can run the same cleanup killEntity would. The entity\n// component must be part of the system's query for its block to be available here.\nexport default function killEntityWorker(entityId: number, components: EntityUpdateComponents, callbacks: ComponentSystemCallbacks): void {\n\tconst block = (components as { entity?: ComponentTypedArray }).entity;\n\tif(block) {\n\t\tblock[DEAD_INDEX] = 1;\n\t}\n\n\tcallbacks.entityDied(entityId);\n}\n","import type { ComponentSystemCallbacks, CreateEntityConfig } from '../systems/component-system';\n\n// The worker-thread counterpart of loadEntity. Called from inside a component system's update function, it\n// can't build the entity itself (eid generation, shared-memory allocation, and factory expansion all live on\n// the main thread), so it buffers the flat config through the callbacks. The main thread creates the entity\n// via world.loadEntity once the run completes, meaning it first exists on the following frame.\nexport default function createEntityWorker(config: CreateEntityConfig, callbacks: ComponentSystemCallbacks): void {\n\tcallbacks.createEntity(config);\n}\n","import type ComponentWorkerMessage from './component-worker-message';\nimport type { ComponentMap } from '../../component-definition';\nimport type { ComponentSystemCallbacks, ComponentSystemWorld, EntityQueryComponents, EntityUpdateComponents, EntityUpdateFunction, QueryDelta, UpdateEntityConfigObject } from '../component-system';\nimport { applyQueryDelta } from './apply-query-delta';\n\n// The slice of the Web Worker global scope createComponentWorker actually touches. Worker files pass the\n// real `self` (e.g. `createComponentWorker(self, fn)`); passing it explicitly also lets test runners that\n// inject `self` as a module local rather than a true global - like @vitest/web-worker - drive the worker.\nexport interface ComponentWorkerScope {\n\tonmessage: ((e: MessageEvent) => void) | null\n\tpostMessage(message: ComponentWorkerMessage): void\n}\n\n// Entry point a game's worker file calls with its update function. It wires up `scope.onmessage`,\n// caches component blocks by entity id (so subsequent runs only need the id), and posts results back.\nexport default function createComponentWorker<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n>(scope: ComponentWorkerScope, updateFunction: EntityUpdateFunction<C, T, W>) {\n\t// The worker's persistent iteration lists. The main thread now sends only membership changes, so these are\n\t// carried across runs and mutated by the deltas each run brings (see applyQueryDelta).\n\tlet entities: Array<UpdateEntityConfigObject<T>> = [];\n\tconst queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\n\tscope.onmessage = function(e) {\n\t\tconst message = e.data as ComponentWorkerMessage<W>;\n\n\t\tif(message.type === 'init') {\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\t\t\tlet createdEntities: Array<Record<string, unknown>> = [];\n\n\t\t\tentities = applyQueryDelta(entities, message.entities as QueryDelta<T>);\n\n\t\t\tlet queries: EntityQueryComponents<C> = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, delta]) => {\n\t\t\t\tconst list = applyQueryDelta(queryEntities[queryKey] ?? [], delta as QueryDelta<T>);\n\t\t\t\tqueryEntities[queryKey] = list;\n\t\t\t\tqueries[queryKey] = list;\n\t\t\t});\n\n\t\t\tlet callbacks: ComponentSystemCallbacks<C> = {\n\t\t\t\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'component-property-updated',\n\t\t\t\t\t\targs: [componentName, prop, value],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\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(updateFunction.preRun) {\n\t\t\t\tupdateFunction.preRun(message.world, entities, queries, callbacks);\n\t\t\t}\n\n\t\t\tentities.forEach(entity => {\n\t\t\t\tupdateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t});\n\n\t\t\t// applyQueryDelta already dropped the removed entities from the persistent lists above; the hook just\n\t\t\t// lets the update function react to entities that left the system's main query.\n\t\t\tif(updateFunction.entityRemoved) {\n\t\t\t\tmessage.entities.removed.forEach(entityId => {\n\t\t\t\t\tupdateFunction.entityRemoved!(message.world, entityId, callbacks);\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst runTime = performance.now() - start;\n\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction postMessageTyped(scope: ComponentWorkerScope, message: ComponentWorkerMessage) {\n\tscope.postMessage(message);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"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/apply-query-delta.ts","../src/systems/workers/component-web-worker.ts","../src/systems/component-system.ts","../src/entity-component.ts","../src/entity.ts","../src/entity-factory.ts","../src/world.ts","../src/actions/kill-entity.ts","../src/actions/kill-entity-worker.ts","../src/actions/create-entity-worker.ts","../src/systems/workers/create-component-worker.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, type MemoryHeap, type TypedArrayConstructor } from '@daneren2005/shared-memory-objects';\n\n// The typed arrays a MemoryComponent can be backed by. Kept narrower than the package's TypedArray\n// union on purpose since these are the only types we allocate blocks of.\nexport type ComponentTypedArray = Uint32Array | Int32Array | Float32Array | Float64Array;\n\n// A pool of same sized blocks living inside a shared MemoryHeap. Each component instance owns one\n// block (referenced by its index) so component data can be shared with worker threads.\nexport default class MemoryComponent<T extends ComponentTypedArray = ComponentTypedArray> {\n\theap: MemoryHeap;\n\tpool: LocalPool<T>;\n\n\tconstructor(heap: MemoryHeap, type: TypedArrayConstructor<T>, dataLength: number) {\n\t\tthis.heap = heap;\n\t\tthis.pool = new LocalPool(heap, {\n\t\t\ttype,\n\t\t\tdataLength,\n\t\t});\n\t}\n\n\tget length() {\n\t\treturn this.pool.length;\n\t}\n\tget rawLength() {\n\t\treturn this.pool.bufferLength;\n\t}\n\n\tcreate(values: Array<number>): number {\n\t\treturn this.pool.push(values);\n\t}\n\n\tgetBlock(index: number): T {\n\t\treturn this.pool.at(index);\n\t}\n\tget(index: number, dataIndex: number): number {\n\t\treturn this.pool.get(index, dataIndex);\n\t}\n\tset(index: number, dataIndex: number, value: number) {\n\t\tlet array = this.pool.at(index);\n\t\tarray[dataIndex] = value;\n\t}\n\n\tdelete(index: number) {\n\t\tthis.pool.deleteIndex(index);\n\t}\n\tclear() {\n\t\tthis.pool.clear();\n\t}\n}\n","import type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\n\n// Base system: runs on an optional fixed timestep (deltaBetweenRuns) and is driven by BaseWorld#update.\n// Systems only care about the component map `C`, not the World's registry (`R`) or config (`Cfg`), so they\n// reference the World through the widened `ComponentDefinitionMap` and let `Cfg` default.\nexport default abstract class System<C extends ComponentMap = ComponentMap> {\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\tthis.name = options.name;\n\t\tthis.world = world;\n\n\t\tthis.deltaBetweenRuns = options.deltaBetweenRuns ?? 0;\n\t\tthis.firstRun = options.firstRun !== undefined ? options.firstRun : false;\n\t}\n\n\tinit(): void | Promise<void> {}\n\n\tclear() {\n\t\tthis.currentDelta = 0;\n\t}\n\tfinishLoading() {}\n\n\tupdate(elapsedTime: number): boolean {\n\t\tthis.currentDelta += elapsedTime;\n\n\t\tif(this.currentDelta >= this.deltaBetweenRuns || this.firstRun) {\n\t\t\tlet leftOverDelta = 0;\n\t\t\tif(this.deltaBetweenRuns > 0) {\n\t\t\t\t// Without this if we take 100ms to run (ie: IterableSystem across multiple frames) then we will end up\n\t\t\t\t// actually running this in 300ms total instead of again in 100ms for a total of 200ms\n\t\t\t\t// With firstRun this ends up calling run(0) the first time - this makes it so things like events are\n\t\t\t\t// will trigger on the second instead of triggering a 1 second timer at 1.0166 seconds\n\t\t\t\tleftOverDelta = this.currentDelta % this.deltaBetweenRuns;\n\t\t\t}\n\n\t\t\tthis.run(this.currentDelta - leftOverDelta);\n\t\t\tthis.currentDelta = leftOverDelta;\n\t\t\tthis.firstRun = false;\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tabstract run(elapsedTime: number): void;\n\n\tshouldRun(): boolean {\n\t\treturn true;\n\t}\n\n\tdestroy() {}\n}\n\nexport interface SystemConfig {\n\tname: string\n\tdeltaBetweenRuns?: number\n\t// Defaults to false\n\tfirstRun?: boolean\n}\n","import type BaseWorld from '../world';\nimport type { ComponentDefinitionMap, ComponentMap } from '../component-definition';\nimport System, { type SystemConfig } from './system';\n\n// A system that iterates a list of instances, spreading the work across multiple frames if a single\n// pass would exceed maxMsPerFrame.\nexport default abstract class IterableSystem<C extends ComponentMap, T> extends System<C> {\n\tremainingInstancesToRun: Array<T> = [];\n\tremainingInstancesStartTime: number | null = null;\n\titerationsPerCheck: number;\n\tmaxMsPerFrame: number;\n\n\tconstructor(world: BaseWorld<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 that own a given set of components on the main thread. Entities are added\n// and removed automatically as the world emits entity-added / entity-removed / component changes.\nexport default abstract class EntitySystem<C extends ComponentMap, T extends BaseEntity<C> = BaseEntity<C>> extends IterableSystem<C, T> {\n\tentities: Array<T> = [];\n\toptions: EntitySystemConfig<C>;\n\n\tconstructor(world: BaseWorld<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\treturn this.entities.filter(entity => !entity.components.entity.dead);\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.indexOf(entity as T) !== -1;\n\t}\n\tabstract updateEntity(entity: T, elapsedTime: number): void;\n\n\tcheckAddEntity(entity: BaseEntity<C>): boolean {\n\t\tif(this.options.components && this.options.components.filter(component => !!entity.components[component]).length !== this.options.components.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif(this.filterEntity(entity)) {\n\t\t\tthis.entities.push(entity as T);\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\tremoveEntity(entity: BaseEntity<C>) {\n\t\tlet index = this.entities.indexOf(entity as T);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t}\n\t}\n\n\tshouldRun(): boolean {\n\t\treturn this.entities.length > 0;\n\t}\n}\n\nexport interface EntitySystemConfig<C extends ComponentMap> extends IterableSystemConfig {\n\tcomponents?: Array<keyof C>\n\tupdateEntityOnAdd?: boolean\n}\n","// Minimal Worker-like base used for the main-thread fallback when real Web Workers / SharedArrayBuffer\n// are unavailable. Params are intentionally loose since this is the (serialization) boundary that\n// mirrors the DOM Worker interface.\nexport default abstract class WebWorker {\n\tabstract postMessage(message: any): void | Promise<void>;\n\tonmessage(message: any, transferrables: Array<any> = []): void {\n\n\t}\n}\n","import type { EntityUpdateComponents, QueryDelta, UpdateEntityConfigObject } from '../component-system';\n\n// A worker keeps one persistent list per query and applies the delta each run carries: drop the entities that\n// left, then upsert the ones that joined (or whose component blocks changed). Because the main thread only\n// sends changes, a steady-state run - where membership is unchanged - carries empty arrays and this returns the\n// existing list untouched with no allocation, which is the whole point of the delta protocol: we stop\n// re-transmitting (and re-cloning) every entity id every single frame.\n//\n// The list is returned (rather than mutated in place) because removals rebuild it via filter; callers must store\n// the returned reference back as their persistent list.\nexport function applyQueryDelta<T extends EntityUpdateComponents>(\n\tlist: Array<UpdateEntityConfigObject<T>>,\n\tdelta: QueryDelta<T>,\n): Array<UpdateEntityConfigObject<T>> {\n\tif(delta.removed.length) {\n\t\tconst removedSet = new Set(delta.removed);\n\t\tlist = list.filter(entry => !removedSet.has(entry.entityId));\n\t}\n\n\tif(delta.added.length) {\n\t\t// Map existing members so a re-added entity (its component set changed) replaces its entry in place\n\t\t// instead of being duplicated; genuinely new entities are appended.\n\t\tconst indexByEid = new Map<number, number>();\n\t\tlist.forEach((entry, index) => indexByEid.set(entry.entityId, index));\n\n\t\tfor(let entity of delta.added) {\n\t\t\tconst existing = indexByEid.get(entity.entityId);\n\t\t\tif(existing !== undefined) {\n\t\t\t\tlist[existing] = entity;\n\t\t\t} else {\n\t\t\t\tindexByEid.set(entity.entityId, list.length);\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn list;\n}\n","import WebWorker from './web-worker';\nimport { applyQueryDelta } from './apply-query-delta';\nimport type ComponentWorkerMessage 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 when real Web Workers /\n// SharedArrayBuffer are unavailable. It runs in-process but still keeps persistent per-query lists and applies\n// the same membership deltas the real worker does, so both backends stay behavior-identical.\nexport default class ComponentWebWorker<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> extends WebWorker {\n\tprivate updateFunction: EntityUpdateFunction<C, T, W>;\n\tprivate entities: Array<UpdateEntityConfigObject<T>> = [];\n\tprivate queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\n\tconstructor(updateFunction: EntityUpdateFunction<C, T, W>) {\n\t\tsuper();\n\t\tthis.updateFunction = updateFunction;\n\t}\n\n\tpostMessage(message: ComponentWorkerMessage<W>): void {\n\t\tif(message.type === 'init') {\n\t\t\tthis.onMessageTyped({\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\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\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\tthis.onMessageTyped({\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime: 0,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t});\n\t\t}\n\t}\n\n\tonMessageTyped(message: ComponentWorkerMessage<W>) {\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, ideally on a\n// separate thread. When Web Workers + SharedArrayBuffer are available the work happens on `getWorker()`;\n// otherwise it falls back to running synchronously on the main thread via ComponentWebWorker.\n//\n// This is deliberately free of any game concepts (no factions, fog of war, position, etc). Games\n// inject whatever extra per-run data they need through `addDataToWorld`.\nexport default abstract class ComponentSystem<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n> extends System<C> {\n\tentities: Array<BaseEntity<C>> = [];\n\toptions: ComponentSystemConfig<C, T, W>;\n\n\tworker: Worker | ComponentWebWorker<C, T, W>;\n\tisWorkerThread: boolean;\n\n\tprivate loaded = false;\n\tprivate loadingPromise: { promise: Promise<void>, resolve: (value: void | PromiseLike<void>) => void } | null = null;\n\tprivate isRunning = false;\n\tprivate queryEntities: { [key: string]: Array<BaseEntity<C>> } = {};\n\t// Per-query membership changes accumulated since the last run(). Each run() flushes these to the worker as a\n\t// delta - added entities carry their component blocks, removed carry just their eid - so a steady-state run\n\t// (unchanged membership) sends empty arrays instead of re-transmitting every entity id every single frame.\n\t// The worker keeps its own persistent list and applies these deltas to it (see applyQueryDelta).\n\tprivate queryDeltas: { [key: string]: MembershipDelta<C> } = {};\n\n\t// Optional hook for subclasses to attach extra data to the world object sent to the worker. Subclasses\n\t// declare the concrete shape through `W` and fill in its fields here.\n\taddDataToWorld?(world: W): void;\n\n\tconstructor(world: BaseWorld<ComponentDefinitionMap, C>, options: ComponentSystemConfig<C, T, W>) {\n\t\tsuper(world, options);\n\t\tthis.options = options;\n\t\tObject.keys(this.options.queries ?? {}).forEach(queryName => {\n\t\t\tthis.queryEntities[queryName] = [];\n\t\t});\n\n\t\tworld.on('entity-added', (entity: BaseEntity<C>) => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\t\tworld.on('entity-removed', (entity: BaseEntity<C>) => {\n\t\t\tthis.removeEntity(entity);\n\t\t});\n\n\t\tworld.entities.forEach(entity => {\n\t\t\tthis.checkAddEntity(entity);\n\t\t});\n\n\t\tif(!options.forceMainThread && typeof globalThis.Worker !== 'undefined' && typeof globalThis.SharedArrayBuffer !== 'undefined') {\n\t\t\tthis.worker = options.getWorker();\n\t\t\tthis.isWorkerThread = true;\n\t\t} else {\n\t\t\tthis.worker = new ComponentWebWorker(options.updateFunction);\n\t\t\tthis.isWorkerThread = false;\n\t\t}\n\n\t\tthis.initWorker();\n\t}\n\n\tprivate initWorker() {\n\t\tthis.worker.onmessage = (e: MessageEvent) => {\n\t\t\tlet message = e.data as ComponentWorkerMessage;\n\t\t\tif(message.type === 'loaded') {\n\t\t\t\tthis.loaded = true;\n\t\t\t\tif(this.loadingPromise) {\n\t\t\t\t\tthis.loadingPromise.resolve();\n\t\t\t\t\tthis.loadingPromise = null;\n\t\t\t\t}\n\t\t\t} else if(message.type === 'run-complete') {\n\t\t\t\tthis.isRunning = false;\n\t\t\t\tif(this.isWorkerThread) {\n\t\t\t\t\tthis.world.emit(`system-${this.name}-worker-finished`, message.runTime);\n\t\t\t\t}\n\n\t\t\t\tmessage.events.forEach(event => {\n\t\t\t\t\t// A system can report events (deaths, component changes) for entities it only knows through a\n\t\t\t\t\t// sub-query - e.g. a collision system that kills a station it found in a spatial query but that\n\t\t\t\t\t// isn't in its main query. Look the entity up on the world so those still route even when the\n\t\t\t\t\t// entity was never part of this system's main query cache.\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(`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// Fulfill any creation requests after deaths, so an entity created this run isn't immediately removed.\n\t\t\t\t// loadEntity runs the full factory expansion + finishLoading and emits `entity-added`, so every system\n\t\t\t\t// (including this one) picks the new entity up on the next run.\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\tif(this.isWorkerThread) {\n\t\t\t\t\tthis.world.emit(`system-${this.name}-worker-events-finished`, message.runTime);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst message: ComponentWorkerMessage = {\n\t\t\ttype: 'init',\n\t\t};\n\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tinit(): Promise<void> | void {\n\t\tif(this.loaded) {\n\t\t\treturn;\n\t\t} else if(this.loadingPromise) {\n\t\t\treturn this.loadingPromise.promise;\n\t\t}\n\n\t\tlet { promise, resolve } = Promise.withResolvers<void>();\n\t\tthis.loadingPromise = {\n\t\t\tpromise,\n\t\t\tresolve,\n\t\t};\n\t\treturn promise;\n\t}\n\n\tupdate(elapsedTime: number): boolean {\n\t\t// Only run worker if the last run completed already\n\t\tif(this.isRunning) {\n\t\t\tthis.currentDelta += elapsedTime;\n\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn super.update(elapsedTime);\n\t\t}\n\t}\n\trun(elapsedTime: number): void {\n\t\t// gameTime + elapsedTime are the only fields the base guarantees; addDataToWorld fills in the rest of `W`,\n\t\t// so the literal is built as the base shape and widened to W for that hook to complete.\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\tworld,\n\t\t\tentities,\n\t\t\tqueries,\n\t\t};\n\t\tthis.worker.postMessage(message);\n\t}\n\n\t// Flushes the pending membership changes for a query into the delta the worker applies to its persistent\n\t// list. Added entities are resolved to their shared-memory component blocks here (the only per-frame cost\n\t// left, and only for entities that actually joined/changed); removed entities are sent as bare eids. The\n\t// buffers are reset so the next run only carries what changed since this one.\n\tprivate buildQueryDelta(queryName: string, query: ComponentSystemQuery<C>): QueryDelta<T> {\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tconst added = delta.added.map(entity => ({\n\t\t\tentityId: entity.eid,\n\t\t\tcomponents: this.buildComponents(entity, query),\n\t\t}));\n\t\tconst removed = delta.removed;\n\t\tthis.queryDeltas[queryName] = { added: [], removed: [] };\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.indexOf(entity) !== -1;\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: [], removed: [] };\n\t\t}\n\n\t\treturn delta;\n\t}\n\t// Records that an entity now belongs to a query, so the next run() sends its (possibly changed) component\n\t// blocks. An entity queued for removal this same frame is un-queued instead: the worker never learned it\n\t// left, so the net effect is a re-send of fresh components rather than a remove+add churn.\n\tprivate markAdded(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tconst removedIndex = delta.removed.indexOf(entity.eid);\n\t\tif(removedIndex !== -1) {\n\t\t\tdelta.removed.splice(removedIndex, 1);\n\t\t}\n\t\tif(delta.added.indexOf(entity) === -1) {\n\t\t\tdelta.added.push(entity);\n\t\t}\n\t}\n\t// Records that an entity left a query. If it was only queued to be added this same frame (never sent to the\n\t// worker), we just drop the pending add - the worker never knew about it, so there is nothing to remove.\n\tprivate markRemoved(delta: MembershipDelta<C>, entity: BaseEntity<C>) {\n\t\tconst addedIndex = delta.added.indexOf(entity);\n\t\tif(addedIndex !== -1) {\n\t\t\tdelta.added.splice(addedIndex, 1);\n\t\t\treturn;\n\t\t}\n\t\tif(delta.removed.indexOf(entity.eid) === -1) {\n\t\t\tdelta.removed.push(entity.eid);\n\t\t}\n\t}\n\tprivate updateEntityList(queryName: string, list: Array<BaseEntity<C>>, entity: BaseEntity<C>, shouldInclude: boolean) {\n\t\tconst index = list.indexOf(entity);\n\t\tconst delta = this.getQueryDelta(queryName);\n\t\tif(shouldInclude) {\n\t\t\tif(index === -1) {\n\t\t\t\tlist.push(entity);\n\t\t\t}\n\t\t\t// Always (re)queue the component blocks: the entity either just joined or a relevant component was\n\t\t\t// added/removed, so the blocks the worker holds for it may be stale.\n\t\t\tthis.markAdded(delta, entity);\n\t\t} else if(index !== -1) {\n\t\t\tlist.splice(index, 1);\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] = []);\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.length > 0;\n\t}\n\n\tdestroy() {\n\t\tif('terminate' in this.worker) {\n\t\t\tthis.worker.terminate();\n\t\t}\n\t}\n}\n\nexport type EntityUpdateComponents<C extends ComponentMap = ComponentMap> = { [K in keyof C]?: ComponentTypedArray };\nexport type EntityQueryComponents<C extends ComponentMap = ComponentMap> = { [key: string]: Array<{ entityId: number, components: EntityUpdateComponents<C> }> };\ntype EntityUpdateFunctionImpl<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> = (\n\tworld: W,\n\tentityId: number,\n\tcomponents: T,\n\tqueries: EntityQueryComponents<C>,\n\tcallbacks: ComponentSystemCallbacks<C>,\n) => void;\n// `T` is required (no default) so every update function must spell out exactly which components it operates on\n// and their concrete typed arrays, rather than falling back to the full component list. `W` is the concrete\n// per-run world shape the owning system builds in addDataToWorld; it defaults to the bare ComponentSystemWorld.\nexport type EntityUpdateFunction<C extends ComponentMap, T extends EntityUpdateComponents<C>, W extends ComponentSystemWorld = ComponentSystemWorld> = EntityUpdateFunctionImpl<C, T, W> & {\n\tpreRun?: EntityUpdatePreRunFunction<C, T, W>\n\tentityRemoved?: EntityRemovedFunction<C, W>\n};\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\n// The membership changes for a single query since the last run, in the shape sent to the worker: entities that\n// joined (or whose component set changed) with their resolved component blocks, and the eids of entities that\n// left. Empty on a steady-state run, which is what keeps the per-frame postMessage small.\nexport interface QueryDelta<T extends EntityUpdateComponents = EntityUpdateComponents> {\n\tadded: Array<UpdateEntityConfigObject<T>>\n\tremoved: Array<number>\n}\n// The main thread's pre-serialization form of a QueryDelta: it holds the live entities (so their component\n// blocks can be resolved lazily at run time), whereas QueryDelta holds the resolved blocks that cross the wire.\ninterface MembershipDelta<C extends ComponentMap> {\n\tadded: Array<BaseEntity<C>>\n\tremoved: Array<number>\n}\n\n// Base per-run world data. gameTime + elapsedTime are always present; games attach anything else\n// they need via addDataToWorld, declaring the concrete shape through the `W` type parameter that\n// ComponentSystem (and its update function) are generic over.\nexport interface ComponentSystemWorld {\n\tgameTime: number\n\telapsedTime: number\n}\n// A flat entity config a worker asks the main thread to create. Kept as a plain record (not the game's `Cfg`)\n// because ComponentSystem is generic over `C`, not `Cfg`; the main thread hands it straight to world.loadEntity,\n// whose factory expands its `type` against the registered templates.\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\tentityDied(entityId: number): void\n\t// Requests that the main thread create an entity from `config` once the run completes. Unlike killing (which\n\t// flips an existing shared-memory flag in place), creation can't happen in the worker, so it is deferred to the\n\t// main thread where eid generation, allocation, and factory expansion already live.\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> extends SystemConfig, ComponentSystemQuery<C> {\n\tupdateFunction: EntityUpdateFunction<C, T, W>\n\tgetWorker: () => Worker\n\tforceMainThread?: boolean\n\n\tqueries?: { [key: string]: ComponentSystemQuery<C> }\n}\n\n// Re-exported so BaseComponent is reachable from the systems barrel if needed.\nexport type { BaseComponent };\n","import type { ComponentDefinition } from './component-definition';\n\n// The one component every entity is required to have. `dead` and `isStatic` are boolean flags stored in\n// the shared-memory block so a worker that pulls the `entity` component into its query can read them too.\n// `type` is a plain string that names the EntityFactory template this entity was built from; it lives off\n// to the side (not in shared memory), so - unlike `dead`/`isStatic` - it is NOT visible to workers.\n// Games that need a stable string id (or any other per-entity data) add their own component for it.\nexport interface EntityComponent {\n\tindex: number\n\ttype: string\n\tdead: boolean\n\tisStatic: boolean\n}\n\n// The defining config for the entity component. `type` is required - every entity is created from a factory\n// template, named by its type - while `isStatic` is an optional flag supplied up front.\nexport interface EntityComponentConfig {\n\ttype: string\n\tisStatic?: boolean\n}\n\n// Runtime-derived state plus `type`: `dead` is only meaningful once the entity is alive, and `type` is kept\n// so a save can be re-expanded through the factory. `isStatic` is intentionally absent - it comes back from\n// the type's template config, not the save.\nexport interface EntityComponentSerialization {\n\ttype?: string\n\tdead?: boolean\n}\n\nexport const DEAD_INDEX = 0;\nexport const STATIC_INDEX = 1;\n\nexport const entityDefinition: ComponentDefinition<EntityComponent, Uint32Array, EntityComponentConfig, EntityComponentSerialization> = {\n\ttype: Uint32Array,\n\tsize: 2,\n\t// The entity component is always loaded by BaseEntity's constructor, so this never actually gates\n\t// loading; it documents the defining config props and keeps it consistent with game components.\n\tloadProperties: ['type', 'isStatic'],\n\tload(entity, memory, config) {\n\t\tconst index = memory.create([config.dead ? 1 : 0, config.isStatic ? 1 : 0]);\n\t\tconst block = memory.getBlock(index);\n\n\t\treturn {\n\t\t\tindex,\n\t\t\t// Plain (non-memory) property, so it is main-thread only and not readable from workers.\n\t\t\ttype: config.type,\n\t\t\tget dead() {\n\t\t\t\treturn block[DEAD_INDEX] === 1;\n\t\t\t},\n\t\t\tset dead(value: boolean) {\n\t\t\t\tblock[DEAD_INDEX] = value ? 1 : 0;\n\t\t\t},\n\t\t\tget isStatic() {\n\t\t\t\treturn block[STATIC_INDEX] === 1;\n\t\t\t},\n\t\t\tset isStatic(value: boolean) {\n\t\t\t\tblock[STATIC_INDEX] = value ? 1 : 0;\n\t\t\t},\n\t\t};\n\t},\n\tsave(component) {\n\t\t// `type` + `dead` are serialized; `isStatic` (and the rest of the template) come back from the type's\n\t\t// config on reload, so they are deliberately left out.\n\t\tconst config: EntityComponentSerialization = {};\n\t\tif(component.type) {\n\t\t\tconfig.type = component.type;\n\t\t}\n\t\tif(component.dead) {\n\t\t\tconfig.dead = true;\n\t\t}\n\n\t\treturn config;\n\t},\n};\n","import { EventEmitter } from 'eventemitter3';\nimport type BaseWorld from './world';\nimport type { ComponentDefinitionMap, ComponentMap, RegisteredComponentRegistry } from './component-definition';\nimport type { EntityComponent } from './entity-component';\n\n// A bare entity: an eid and a bag of memory-backed components (including the required entity component).\n// `Cfg` is the flat config this entity loads from / saves to; it defaults to `any` so a bare `BaseEntity<C>`\n// stays usable, but a World derives it (via `EntityConfigOf`) so `config` and `load` are fully typed.\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\t// The World only uses its `R` param to derive `C`/`Cfg`, so entities reference it Cfg-agnostically via the\n\t// widened `ComponentDefinitionMap` - the instance shape depends on `C`/`Cfg`, not on the concrete registry.\n\tworld: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\t// The entity component is required on every entity, so it is always present (unlike the game\n\t// components, which are partial). Its `dead`/`isStatic` flags and `id` live here now.\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\t// `emitAdded` is true for runtime additions so systems can react; the loading path (constructor and\n\t// `load`) passes false, since those components are already accounted for when the entity is added.\n\tloadComponent<K extends keyof C>(name: K, config: any, emitAdded = true): C[K] {\n\t\t// registry carries the always-present entity component as an intersection; index the plain game map\n\t\t// here so the generic key stays cleanly typed as C[K].\n\t\tconst definition = (this.world.registry as RegisteredComponentRegistry<C>)[name];\n\t\t// The definition now owns its MemoryComponent, so the memory pool comes straight off it.\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// TS can't verify writing to a property of the generic C[K] by a keyof C[K] key, so index through a record.\n\t\t(component as unknown as Record<P, C[K][P]>)[prop] = value;\n\t\tthis.emit('component-property-updated', componentName, prop, value);\n\t}\n\t/**\n\t * NOTE: Does not emit component-property-updated!\n\t */\n\tsetComponentBulk<K extends keyof C>(componentName: K, values: Partial<C[K]>) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tObject.assign(component, values);\n\t}\n\tdeleteComponent<K extends keyof C>(componentName: K, prop: keyof C[K]) {\n\t\tconst component = this.components[componentName];\n\t\tif(!component) {\n\t\t\treturn;\n\t\t}\n\n\t\tdelete (component as Partial<C[K]>)[prop];\n\t\tthis.emit('component-property-deleted', componentName, prop);\n\t}\n\n\tdeleteAllComponentMemory() {\n\t\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\t// Loads component data from a flat config: every registered component whose `loadProperties` appear in\n\t// the config is handed the entire config. The entity component is skipped here since the constructor\n\t// always loads it up front.\n\tload(config: Cfg) {\n\t\t// The flat config is keyed by string props; index it as a record for the `loadProperties` checks.\n\t\tconst props = config as Record<string, unknown>;\n\t\t// registry carries the intersected entity component; index the plain game map so `definition` stays typed.\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\t// Deferred components wait for finishLoading, once every entity in the batch exists.\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\t// Every component's saver returns flat props merged into one shared config, mirroring how `load`\n\t\t// hands that same flat config to each loader.\n\t\tconst config: { [key: string]: any } = {};\n\n\t\t// registry carries the intersected entity component; index the plain game map here (the entity key\n\t\t// still resolves at runtime, so its definition is picked up as well).\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\t// The merged serialization slices reconstruct a (partial) flat config, which is exactly `Cfg`.\n\t\treturn config as Cfg;\n\t}\n\t// Hook for games that need a second pass once every entity in a load batch exists. The base pass loads any\n\t// components flagged `loadInFinishLoading`, which `load` deliberately 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` name to a base (template) config. Loading an entity of a given type layers the\n// caller's config on top of that base, so shared static data (a goblin's maxHealth, say) is declared once\n// here instead of being saved on every entity - a save then only needs the `type` plus the entity's runtime\n// serialization. BaseWorld#loadEntity goes through the factory, so every load is type-expanded.\nexport default class EntityFactory<C extends ComponentMap = ComponentMap, Cfg = any> {\n\t// Set by BaseWorld when the factory is attached to it. The World only uses `R` to derive `C`/`Cfg`, so the\n\t// factory references it Cfg-agnostically through the widened `ComponentDefinitionMap`.\n\tworld!: BaseWorld<ComponentDefinitionMap, C, Cfg>;\n\t// type name -> its base config.\n\tconfigs: { [type: string]: Cfg };\n\n\tconstructor(configs: { [type: string]: Cfg } = {}) {\n\t\tthis.configs = configs;\n\t}\n\n\t// Register (or replace) the base config for an entity type.\n\tregister(type: string, config: Cfg) {\n\t\tthis.configs[type] = config;\n\t}\n\n\t// Layer a config over its type's base config. A config with no (or an unknown) `type` passes through\n\t// unchanged, so fully-specified configs can still be loaded directly.\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\t// Build a type-expanded entity and add it to the world.\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\t// Hook for games that map types to BaseEntity subclasses; override to return a subclass per config.type.\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 { MAX_BYTE_OFFSET_LENGTH, MemoryHeap } from '@daneren2005/shared-memory-objects';\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\t// Supplies the type -> base config templates; defaults to an empty factory that loads configs as-is.\n\tfactory?: EntityFactory<C, Cfg>\n}\n\n// The serialized shape of a whole world: the flat list of entity configs to (re)build plus the world clocks. A\n// game can layer its own fields on top; the World itself only needs `entities` (the same flat `Cfg` objects\n// `loadEntity` / `save` deal with) and the optional time state that `load` restores.\nexport interface WorldConfig<Cfg = any> {\n\tentities: Array<Cfg>\n\t// Simulation clock; restored so a saved world resumes at the same in-game time. Defaults to 0.\n\tgameTime?: number\n\t// Real elapsed play time; kept separate from gameTime and unaffected by timeScale. Defaults to 0.\n\tplayerTime?: number\n\t// Simulation speed multiplier. Defaults to 1.\n\ttimeScale?: number\n}\n\n// A simple wrapper around a set of entities + systems. On construction it creates one\n// MemoryComponent per entry in the component registry so entities can load/save themselves without\n// each game re-declaring loaders/savers. It has no game specific load/save/terrain/faction logic -\n// that all belongs in the game that consumes this library.\n// The World is generic over `R`, the registry of component definitions a game supplies. Both the\n// component-instance map `C` and the flat entity config `Cfg` are derived from `R` (via `ComponentsOf` /\n// `EntityConfigOf`) and default off it, so `new BaseWorld(registry)` infers `R` from its argument and every\n// entity's components and config are typed without the game declaring any composite types by hand.\nexport default class BaseWorld<\n\tR extends ComponentDefinitionMap = ComponentDefinitionMap,\n\tC extends ComponentMap = ComponentsOf<R>,\n\tCfg = EntityConfigOf<R>,\n> extends EventEmitter {\n\theap: MemoryHeap;\n\t// The entity component is always registered on top of the game's components so every entity can be\n\t// given one automatically. Each registered definition carries its own MemoryComponent, so a\n\t// component's memory pool is reachable straight from `registry[name].memoryComponent`.\n\tregistry: RegisteredComponentRegistry<C> & { entity: RegisteredComponentDefinition<EntityComponent> };\n\t// Every entity is built through the factory, which expands its `type` against the registered templates.\n\tfactory: EntityFactory<C, Cfg>;\n\n\tentities: Array<BaseEntity<C, Cfg>> = [];\n\tentitiesByEid: { [eid: number]: BaseEntity<C, Cfg> } = {};\n\tsystems: Array<System<C>> = [];\n\n\tgameTime = 0;\n\t// Real (unscaled) time the player has spent in the world. Unlike gameTime it keeps advancing while paused and\n\t// is never multiplied by timeScale.\n\tplayerTime = 0;\n\t// Multiplier applied to elapsedTime before it advances gameTime / runs systems, so a game can speed up or slow\n\t// down simulation without touching the real frame delta.\n\ttimeScale = 1;\n\t// While paused, update still accrues playerTime but skips advancing gameTime and running systems.\n\tpaused = false;\n\tdestroyed = false;\n\n\t// The game supplies its own components as `R`; the entity component is added automatically, so it must not\n\t// 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\t// Register every supplied definition (plus the always-present entity component) by attaching a freshly\n\t\t// allocated MemoryComponent to it, so the memory pool lives alongside the definition on the registry.\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\n\taddEntity(entity: BaseEntity<C, Cfg>, created = true): BaseEntity<C, Cfg> {\n\t\tthis.entities.push(entity);\n\t\tthis.entitiesByEid[entity.eid] = entity;\n\t\tentity.world = this;\n\n\t\tentity.on('component-added', (name: keyof C) => {\n\t\t\tthis.addEntityToComponentSystem(entity, name);\n\t\t});\n\t\tentity.on('component-removed', (name: keyof C) => {\n\t\t\tthis.removeEntityFromComponentSystem(entity, name);\n\t\t});\n\n\t\tif(created) {\n\t\t\tentity.finishLoading();\n\t\t\tthis.emit('entity-added', entity);\n\t\t\t// killEntity / killEntityWorker flag the entity dead and emit `death`; remove it here.\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\t// The factory expands the config's `type` against the registered templates before building the entity.\n\t\treturn this.factory.loadEntity(config, created);\n\t}\n\t// Replace the world's contents with a saved config. The existing entities (their backing memory freed) are\n\t// cleared and each system is reset via `clear()` first, then each entity is loaded with `created = false` so\n\t// no finishLoading runs mid-batch. Systems themselves are set up once ahead of time (they persist across\n\t// loads); only their per-load state is cleared here. Once every entity exists, finishLoading is called on\n\t// each - so a component that depends on other entities (e.g. a lumbermill counting nearby trees) can resolve\n\t// them, since the whole batch is guaranteed loaded by then.\n\tload(config: WorldConfig<Cfg>) {\n\t\t// Iterate over a copy since removeEntity mutates `this.entities`.\n\t\tfor(let entity of this.entities.slice()) {\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\t// killEntity / killEntityWorker flag the entity dead and emit `death`; remove it here.\n\t\t\tentity.on('death', () => {\n\t\t\t\tthis.onEntityDied(entity);\n\t\t\t});\n\t\t}\n\n\t\t// Restore the world clocks, falling back to a fresh world's defaults when the config omits them.\n\t\tthis.gameTime = config.gameTime ?? 0;\n\t\tthis.playerTime = config.playerTime ?? 0;\n\t\tthis.timeScale = config.timeScale ?? 1;\n\t}\n\tremoveEntity(entity: BaseEntity<C, Cfg>) {\n\t\tlet index = this.entities.indexOf(entity);\n\t\tif(index !== -1) {\n\t\t\tthis.entities.splice(index, 1);\n\t\t\tdelete this.entitiesByEid[entity.eid];\n\t\t\tthis.emit('entity-removed', entity);\n\t\t}\n\n\t\tentity.deleteAllComponentMemory();\n\t}\n\tonEntityDied(entity: BaseEntity<C, Cfg>) {\n\t\tthis.removeEntity(entity);\n\t}\n\tgetEntityByEid(eid: number): BaseEntity<C, Cfg> | undefined {\n\t\treturn this.entitiesByEid[eid];\n\t}\n\n\taddSystem<T extends System<C>>(system: T): T {\n\t\tthis.systems.push(system);\n\t\treturn system;\n\t}\n\taddSystemIfNotExists(system: System<C>) {\n\t\tlet index = this.systems.findIndex(otherSystem => system.name === otherSystem.name);\n\t\tif(index === -1) {\n\t\t\tthis.systems.push(system);\n\t\t}\n\t}\n\tremoveSystem(name: string) {\n\t\tlet index = this.systems.findIndex(system => system.name === name);\n\t\tif(index !== -1) {\n\t\t\tthis.systems.splice(index, 1);\n\t\t}\n\t}\n\n\tupdate(elapsedTime: number): { lastSystemError?: Error | null } {\n\t\t// playerTime tracks real elapsed time and keeps ticking even while paused; gameTime is the scaled,\n\t\t// pausable simulation clock the systems run against.\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// Kills an entity on the main thread: flags it dead in shared memory and emits `death` so the world and\n// any game listeners can react. BaseWorld#addEntity listens for `death` to remove the entity.\nexport default function killEntity(entity: BaseEntity): void {\n\tentity.components.entity.dead = true;\n\tentity.emit('death');\n}\n","import type { ComponentTypedArray } from '../memory-component';\nimport type { ComponentSystemCallbacks, EntityUpdateComponents } from '../systems/component-system';\nimport { DEAD_INDEX } from '../entity-component';\n\n// The worker-thread counterpart of killEntity. Called from inside a component system's update function,\n// it flags the entity dead directly in its shared-memory block and reports the death back to the main\n// thread through the callbacks so the world can run the same cleanup killEntity would. The entity\n// component must be part of the system's query for its block to be available here.\nexport default function killEntityWorker(entityId: number, components: EntityUpdateComponents, callbacks: ComponentSystemCallbacks): void {\n\tconst block = (components as { entity?: ComponentTypedArray }).entity;\n\tif(block) {\n\t\tblock[DEAD_INDEX] = 1;\n\t}\n\n\tcallbacks.entityDied(entityId);\n}\n","import type { ComponentSystemCallbacks, CreateEntityConfig } from '../systems/component-system';\n\n// The worker-thread counterpart of loadEntity. Called from inside a component system's update function, it\n// can't build the entity itself (eid generation, shared-memory allocation, and factory expansion all live on\n// the main thread), so it buffers the flat config through the callbacks. The main thread creates the entity\n// via world.loadEntity once the run completes, meaning it first exists on the following frame.\nexport default function createEntityWorker(config: CreateEntityConfig, callbacks: ComponentSystemCallbacks): void {\n\tcallbacks.createEntity(config);\n}\n","import type ComponentWorkerMessage from './component-worker-message';\nimport type { ComponentMap } from '../../component-definition';\nimport type { ComponentSystemCallbacks, ComponentSystemWorld, EntityQueryComponents, EntityUpdateComponents, EntityUpdateFunction, QueryDelta, UpdateEntityConfigObject } from '../component-system';\nimport { applyQueryDelta } from './apply-query-delta';\n\n// The slice of the Web Worker global scope createComponentWorker actually touches. Worker files pass the\n// real `self` (e.g. `createComponentWorker(self, fn)`); passing it explicitly also lets test runners that\n// inject `self` as a module local rather than a true global - like @vitest/web-worker - drive the worker.\nexport interface ComponentWorkerScope {\n\tonmessage: ((e: MessageEvent) => void) | null\n\tpostMessage(message: ComponentWorkerMessage): void\n}\n\n// Entry point a game's worker file calls with its update function. It wires up `scope.onmessage`,\n// caches component blocks by entity id (so subsequent runs only need the id), and posts results back.\nexport default function createComponentWorker<\n\tC extends ComponentMap,\n\tT extends EntityUpdateComponents<C>,\n\tW extends ComponentSystemWorld = ComponentSystemWorld,\n>(scope: ComponentWorkerScope, updateFunction: EntityUpdateFunction<C, T, W>) {\n\t// The worker's persistent iteration lists. The main thread now sends only membership changes, so these are\n\t// carried across runs and mutated by the deltas each run brings (see applyQueryDelta).\n\tlet entities: Array<UpdateEntityConfigObject<T>> = [];\n\tconst queryEntities: { [key: string]: Array<UpdateEntityConfigObject<T>> } = {};\n\n\tscope.onmessage = function(e) {\n\t\tconst message = e.data as ComponentWorkerMessage<W>;\n\n\t\tif(message.type === 'init') {\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'loaded',\n\t\t\t});\n\t\t} else if(message.type === 'run') {\n\t\t\tconst start = performance.now();\n\t\t\tlet entityEvents: Array<{ entityId: number, event: string, args: Array<any> }> = [];\n\t\t\tlet createdEntities: Array<Record<string, unknown>> = [];\n\n\t\t\tentities = applyQueryDelta(entities, message.entities as QueryDelta<T>);\n\n\t\t\tlet queries: EntityQueryComponents<C> = {};\n\t\t\tObject.entries(message.queries).forEach(([queryKey, delta]) => {\n\t\t\t\tconst list = applyQueryDelta(queryEntities[queryKey] ?? [], delta as QueryDelta<T>);\n\t\t\t\tqueryEntities[queryKey] = list;\n\t\t\t\tqueries[queryKey] = list;\n\t\t\t});\n\n\t\t\tlet callbacks: ComponentSystemCallbacks<C> = {\n\t\t\t\tentityComponentChanged<K extends keyof C, P extends keyof C[K]>(entityId: number, componentName: K, prop: P, value: C[K][P]) {\n\t\t\t\t\tentityEvents.push({\n\t\t\t\t\t\tentityId,\n\t\t\t\t\t\tevent: 'component-property-updated',\n\t\t\t\t\t\targs: [componentName, prop, value],\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\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(updateFunction.preRun) {\n\t\t\t\tupdateFunction.preRun(message.world, entities, queries, callbacks);\n\t\t\t}\n\n\t\t\tentities.forEach(entity => {\n\t\t\t\tupdateFunction(message.world, entity.entityId, entity.components, queries, callbacks);\n\t\t\t});\n\n\t\t\t// applyQueryDelta already dropped the removed entities from the persistent lists above; the hook just\n\t\t\t// lets the update function react to entities that left the system's main query.\n\t\t\tif(updateFunction.entityRemoved) {\n\t\t\t\tmessage.entities.removed.forEach(entityId => {\n\t\t\t\t\tupdateFunction.entityRemoved!(message.world, entityId, callbacks);\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst runTime = performance.now() - start;\n\n\t\t\tpostMessageTyped(scope, {\n\t\t\t\ttype: 'run-complete',\n\t\t\t\trunTime,\n\t\t\t\tevents: entityEvents,\n\t\t\t\tcreated: createdEntities,\n\t\t\t});\n\t\t}\n\t};\n}\n\nfunction postMessageTyped(scope: ComponentWorkerScope, message: ComponentWorkerMessage) {\n\tscope.postMessage(message);\n}\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
|
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.1.
|
|
5
|
+
"version": "1.1.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -35,8 +35,7 @@
|
|
|
35
35
|
"prepare": "husky"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"
|
|
39
|
-
"eventemitter3": "^3.1.2"
|
|
38
|
+
"eventemitter3": "^5.0.4"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@semantic-release/git": "^10.0.1",
|
|
@@ -52,5 +51,8 @@
|
|
|
52
51
|
"typescript": "^7.0.2",
|
|
53
52
|
"vite": "^8.1.4",
|
|
54
53
|
"vitest": "^4.1.10"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@daneren2005/shared-memory-objects": "^1.0.0"
|
|
55
57
|
}
|
|
56
58
|
}
|