@oasys/oecs 0.2.1 → 0.3.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/LICENSE +1 -1
- package/README.md +169 -182
- package/dist/archetype.d.ts +19 -9
- package/dist/archetype.d.ts.map +1 -1
- package/dist/component.d.ts +10 -0
- package/dist/component.d.ts.map +1 -1
- package/dist/ecs.d.ts +14 -14
- package/dist/ecs.d.ts.map +1 -1
- package/dist/entity.d.ts.map +1 -1
- package/dist/event.d.ts +6 -0
- package/dist/event.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +761 -524
- package/dist/query.d.ts +40 -16
- package/dist/query.d.ts.map +1 -1
- package/dist/ref.d.ts +4 -0
- package/dist/ref.d.ts.map +1 -1
- package/dist/resource.d.ts +21 -21
- package/dist/resource.d.ts.map +1 -1
- package/dist/schedule.d.ts +8 -6
- package/dist/schedule.d.ts.map +1 -1
- package/dist/store.d.ts +13 -6
- package/dist/store.d.ts.map +1 -1
- package/dist/system.d.ts.map +1 -1
- package/dist/type_primitives/assertions.d.ts +1 -0
- package/dist/type_primitives/assertions.d.ts.map +1 -1
- package/dist/type_primitives/binary_heap/binary_heap.d.ts +33 -0
- package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -0
- package/dist/type_primitives/bitset/bitset.d.ts +5 -0
- package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
- package/dist/type_primitives/error.d.ts +2 -1
- package/dist/type_primitives/error.d.ts.map +1 -1
- package/dist/type_primitives/index.d.ts +2 -0
- package/dist/type_primitives/index.d.ts.map +1 -1
- package/dist/type_primitives/topological_sort/topological_sort.d.ts +25 -0
- package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -0
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +2 -0
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
- package/dist/utils/arrays.d.ts.map +1 -1
- package/dist/utils/constants.d.ts +0 -8
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/error.d.ts +4 -1
- package/dist/utils/error.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Z extends Error {
|
|
2
2
|
constructor(t, e, s) {
|
|
3
3
|
super(t), this.is_operational = e, this.context = s, this.name = this.constructor.name, Error.captureStackTrace(this, this.constructor);
|
|
4
4
|
}
|
|
5
5
|
}
|
|
6
|
-
var
|
|
7
|
-
class
|
|
6
|
+
var D = /* @__PURE__ */ ((a) => (a.EID_MAX_INDEX_OVERFLOW = "EID_MAX_INDEX_OVERFLOW", a.EID_MAX_GEN_OVERFLOW = "EID_MAX_GEN_OVERFLOW", a.COMPONENT_NOT_REGISTERED = "COMPONENT_NOT_REGISTERED", a.ENTITY_NOT_ALIVE = "ENTITY_NOT_ALIVE", a.CIRCULAR_SYSTEM_DEPENDENCY = "CIRCULAR_SYSTEM_DEPENDENCY", a.DUPLICATE_SYSTEM = "DUPLICATE_SYSTEM", a.ARCHETYPE_NOT_FOUND = "ARCHETYPE_NOT_FOUND", a.RESOURCE_NOT_REGISTERED = "RESOURCE_NOT_REGISTERED", a.RESOURCE_ALREADY_REGISTERED = "RESOURCE_ALREADY_REGISTERED", a.EVENT_ALREADY_REGISTERED = "EVENT_ALREADY_REGISTERED", a.EVENT_NOT_REGISTERED = "EVENT_NOT_REGISTERED", a))(D || {});
|
|
7
|
+
class O extends Z {
|
|
8
8
|
constructor(t, e, s) {
|
|
9
9
|
super(e ?? t, !0, s), this.category = t;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
return
|
|
12
|
+
function F(a, t, e) {
|
|
13
|
+
return a;
|
|
14
14
|
}
|
|
15
|
-
const
|
|
16
|
-
class
|
|
15
|
+
const I = 5, S = 31, tt = 2166136261, et = 16777619, st = 4;
|
|
16
|
+
class p {
|
|
17
17
|
_words;
|
|
18
18
|
constructor(t) {
|
|
19
|
-
this._words = t ?? new Array(
|
|
19
|
+
this._words = t ?? new Array(st).fill(0);
|
|
20
20
|
}
|
|
21
21
|
has(t) {
|
|
22
|
-
const e = t >>>
|
|
23
|
-
return e >= this._words.length ? !1 : (this._words[e] & 1 << (t &
|
|
22
|
+
const e = t >>> I;
|
|
23
|
+
return e >= this._words.length ? !1 : (this._words[e] & 1 << (t & S)) !== 0;
|
|
24
24
|
}
|
|
25
25
|
set(t) {
|
|
26
|
-
const e = t >>>
|
|
27
|
-
e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t &
|
|
26
|
+
const e = t >>> I;
|
|
27
|
+
e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t & S);
|
|
28
28
|
}
|
|
29
29
|
clear(t) {
|
|
30
|
-
const e = t >>>
|
|
31
|
-
e >= this._words.length || (this._words[e] &= ~(1 << (t &
|
|
30
|
+
const e = t >>> I;
|
|
31
|
+
e >= this._words.length || (this._words[e] &= ~(1 << (t & S)));
|
|
32
32
|
}
|
|
33
33
|
/** True if any bit is set in both this and other (non-empty intersection). */
|
|
34
34
|
overlaps(t) {
|
|
35
35
|
const e = this._words, s = t._words, n = e.length < s.length ? e.length : s.length;
|
|
36
|
-
for (let
|
|
37
|
-
if ((e[
|
|
36
|
+
for (let i = 0; i < n; i++)
|
|
37
|
+
if ((e[i] & s[i]) !== 0) return !0;
|
|
38
38
|
return !1;
|
|
39
39
|
}
|
|
40
40
|
/** True if this is a superset of other (all bits in other are set in this). */
|
|
41
41
|
contains(t) {
|
|
42
42
|
const e = t._words, s = this._words, n = s.length;
|
|
43
|
-
for (let
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
43
|
+
for (let i = 0; i < e.length; i++) {
|
|
44
|
+
const r = e[i];
|
|
45
|
+
if (r !== 0 && (i >= n || (s[i] & r) !== r))
|
|
46
46
|
return !1;
|
|
47
47
|
}
|
|
48
48
|
return !0;
|
|
49
49
|
}
|
|
50
50
|
equals(t) {
|
|
51
51
|
const e = this._words, s = t._words, n = e.length > s.length ? e.length : s.length;
|
|
52
|
-
for (let
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
52
|
+
for (let i = 0; i < n; i++) {
|
|
53
|
+
const r = i < e.length ? e[i] : 0, c = i < s.length ? s[i] : 0;
|
|
54
|
+
if (r !== c) return !1;
|
|
55
55
|
}
|
|
56
56
|
return !0;
|
|
57
57
|
}
|
|
58
58
|
copy() {
|
|
59
|
-
return new
|
|
59
|
+
return new p(this._words.slice());
|
|
60
60
|
}
|
|
61
61
|
copy_with_set(t) {
|
|
62
|
-
const e = t >>>
|
|
63
|
-
for (let
|
|
64
|
-
return
|
|
62
|
+
const e = t >>> I, s = e + 1, n = this._words.length > s ? this._words.length : s, i = new Array(n).fill(0);
|
|
63
|
+
for (let r = 0; r < this._words.length; r++) i[r] = this._words[r];
|
|
64
|
+
return i[e] |= 1 << (t & S), new p(i);
|
|
65
65
|
}
|
|
66
66
|
copy_with_clear(t) {
|
|
67
|
-
const e = this._words.slice(), s = t >>>
|
|
68
|
-
return s < e.length && (e[s] &= ~(1 << (t &
|
|
67
|
+
const e = this._words.slice(), s = t >>> I;
|
|
68
|
+
return s < e.length && (e[s] &= ~(1 << (t & S))), new p(e);
|
|
69
69
|
}
|
|
70
70
|
/** FNV-1a hash. Skips trailing zero words so differently-sized arrays with the same bits hash equally. */
|
|
71
71
|
hash() {
|
|
72
|
-
let t =
|
|
72
|
+
let t = tt;
|
|
73
73
|
const e = this._words;
|
|
74
74
|
let s = e.length - 1;
|
|
75
75
|
for (; s >= 0 && e[s] === 0; ) s--;
|
|
76
76
|
for (let n = 0; n <= s; n++)
|
|
77
|
-
t ^= e[n], t = Math.imul(t,
|
|
77
|
+
t ^= e[n], t = Math.imul(t, et);
|
|
78
78
|
return t;
|
|
79
79
|
}
|
|
80
80
|
/** Iterate all set bits via lowest-set-bit extraction. */
|
|
@@ -83,10 +83,10 @@ class x {
|
|
|
83
83
|
for (let s = 0; s < e.length; s++) {
|
|
84
84
|
let n = e[s];
|
|
85
85
|
if (n === 0) continue;
|
|
86
|
-
const
|
|
86
|
+
const i = s << I;
|
|
87
87
|
for (; n !== 0; ) {
|
|
88
|
-
const
|
|
89
|
-
t(
|
|
88
|
+
const r = n & -n >>> 0, c = S - Math.clz32(r);
|
|
89
|
+
t(i + c), n ^= r;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -98,8 +98,9 @@ class x {
|
|
|
98
98
|
this._words = s;
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
+
const b = 16, X = 2;
|
|
101
102
|
class A {
|
|
102
|
-
constructor(t, e =
|
|
103
|
+
constructor(t, e = 16) {
|
|
103
104
|
this._ctor = t, this._buf = new t(e);
|
|
104
105
|
}
|
|
105
106
|
_buf;
|
|
@@ -158,7 +159,7 @@ class A {
|
|
|
158
159
|
ensure_capacity(t) {
|
|
159
160
|
if (t <= this._buf.length) return;
|
|
160
161
|
let e = this._buf.length || 1;
|
|
161
|
-
for (; e < t; ) e *=
|
|
162
|
+
for (; e < t; ) e *= X;
|
|
162
163
|
const s = new this._ctor(e);
|
|
163
164
|
s.set(this._buf.subarray(0, this._len)), this._buf = s;
|
|
164
165
|
}
|
|
@@ -174,65 +175,151 @@ class A {
|
|
|
174
175
|
this.ensure_capacity(this._len + t), this._buf.fill(0, this._len, this._len + t), this._len += t;
|
|
175
176
|
}
|
|
176
177
|
_grow() {
|
|
177
|
-
const t = new this._ctor(this._buf.length *
|
|
178
|
+
const t = new this._ctor(this._buf.length * X);
|
|
178
179
|
t.set(this._buf), this._buf = t;
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
|
-
class
|
|
182
|
+
class nt extends A {
|
|
182
183
|
constructor(t = b) {
|
|
183
184
|
super(Float32Array, t);
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
|
-
class
|
|
187
|
+
class it extends A {
|
|
187
188
|
constructor(t = b) {
|
|
188
189
|
super(Float64Array, t);
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
|
-
class
|
|
192
|
+
class rt extends A {
|
|
192
193
|
constructor(t = b) {
|
|
193
194
|
super(Int8Array, t);
|
|
194
195
|
}
|
|
195
196
|
}
|
|
196
|
-
class
|
|
197
|
+
class _t extends A {
|
|
197
198
|
constructor(t = b) {
|
|
198
199
|
super(Int16Array, t);
|
|
199
200
|
}
|
|
200
201
|
}
|
|
201
|
-
class
|
|
202
|
+
class ot extends A {
|
|
202
203
|
constructor(t = b) {
|
|
203
204
|
super(Int32Array, t);
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
|
-
class
|
|
207
|
+
class ct extends A {
|
|
207
208
|
constructor(t = b) {
|
|
208
209
|
super(Uint8Array, t);
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
|
-
class
|
|
212
|
+
class ht extends A {
|
|
212
213
|
constructor(t = b) {
|
|
213
214
|
super(Uint16Array, t);
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
|
-
class
|
|
217
|
+
class H extends A {
|
|
217
218
|
constructor(t = b) {
|
|
218
219
|
super(Uint32Array, t);
|
|
219
220
|
}
|
|
220
221
|
}
|
|
221
|
-
const
|
|
222
|
-
f32:
|
|
223
|
-
f64:
|
|
224
|
-
i8:
|
|
225
|
-
i16:
|
|
226
|
-
i32:
|
|
227
|
-
u8:
|
|
228
|
-
u16:
|
|
229
|
-
u32:
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
222
|
+
const at = {
|
|
223
|
+
f32: nt,
|
|
224
|
+
f64: it,
|
|
225
|
+
i8: rt,
|
|
226
|
+
i16: _t,
|
|
227
|
+
i32: ot,
|
|
228
|
+
u8: ct,
|
|
229
|
+
u16: ht,
|
|
230
|
+
u32: H
|
|
231
|
+
};
|
|
232
|
+
class lt {
|
|
233
|
+
_compare;
|
|
234
|
+
_data = [];
|
|
235
|
+
constructor(t) {
|
|
236
|
+
this._compare = t;
|
|
237
|
+
}
|
|
238
|
+
get size() {
|
|
239
|
+
return this._data.length;
|
|
240
|
+
}
|
|
241
|
+
/** Returns the highest-priority element without removing it, or undefined if empty. */
|
|
242
|
+
peek() {
|
|
243
|
+
return this._data[0];
|
|
244
|
+
}
|
|
245
|
+
/** Inserts a value and restores heap order by sifting up. O(log n). */
|
|
246
|
+
push(t) {
|
|
247
|
+
this._data.push(t), this._sift_up(this._data.length - 1);
|
|
248
|
+
}
|
|
249
|
+
/** Removes and returns the highest-priority element, or undefined if empty. O(log n). */
|
|
250
|
+
pop() {
|
|
251
|
+
const t = this._data;
|
|
252
|
+
if (t.length === 0) return;
|
|
253
|
+
const s = t[0], n = t.pop();
|
|
254
|
+
return t.length > 0 && (t[0] = n, this._sift_down(0)), s;
|
|
255
|
+
}
|
|
256
|
+
/** Removes all elements. O(1). */
|
|
257
|
+
clear() {
|
|
258
|
+
this._data.length = 0;
|
|
259
|
+
}
|
|
260
|
+
/** Moves a node up toward the root until heap order is restored. */
|
|
261
|
+
_sift_up(t) {
|
|
262
|
+
const e = this._data, s = this._compare, n = e[t];
|
|
263
|
+
for (; t > 0; ) {
|
|
264
|
+
const i = t - 1 >> 1;
|
|
265
|
+
if (s(n, e[i]) >= 0) break;
|
|
266
|
+
e[t] = e[i], t = i;
|
|
267
|
+
}
|
|
268
|
+
e[t] = n;
|
|
269
|
+
}
|
|
270
|
+
/** Moves a node down away from the root until heap order is restored. */
|
|
271
|
+
_sift_down(t) {
|
|
272
|
+
const e = this._data, s = this._compare, n = e.length, i = n >> 1, r = e[t];
|
|
273
|
+
for (; t < i; ) {
|
|
274
|
+
let c = (t << 1) + 1;
|
|
275
|
+
const o = c + 1;
|
|
276
|
+
if (o < n && s(e[o], e[c]) < 0 && (c = o), s(e[c], r) >= 0) break;
|
|
277
|
+
e[t] = e[c], t = c;
|
|
278
|
+
}
|
|
279
|
+
e[t] = r;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function dt(a, t, e, s) {
|
|
283
|
+
const n = s ?? ((o) => String(o)), i = /* @__PURE__ */ new Map();
|
|
284
|
+
for (let o = 0; o < a.length; o++)
|
|
285
|
+
i.set(a[o], 0);
|
|
286
|
+
for (const [, o] of t)
|
|
287
|
+
for (let _ = 0; _ < o.length; _++) {
|
|
288
|
+
const h = o[_];
|
|
289
|
+
i.has(h) && i.set(h, i.get(h) + 1);
|
|
290
|
+
}
|
|
291
|
+
const r = new lt(e);
|
|
292
|
+
for (let o = 0; o < a.length; o++)
|
|
293
|
+
i.get(a[o]) === 0 && r.push(a[o]);
|
|
294
|
+
const c = [];
|
|
295
|
+
for (; r.size > 0; ) {
|
|
296
|
+
const o = r.pop();
|
|
297
|
+
c.push(o);
|
|
298
|
+
const _ = t.get(o);
|
|
299
|
+
if (_ !== void 0)
|
|
300
|
+
for (let h = 0; h < _.length; h++) {
|
|
301
|
+
const l = _[h];
|
|
302
|
+
if (!i.has(l)) continue;
|
|
303
|
+
const d = i.get(l) - 1;
|
|
304
|
+
i.set(l, d), d === 0 && r.push(l);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (c.length !== a.length) {
|
|
308
|
+
const o = [];
|
|
309
|
+
for (const [_, h] of i)
|
|
310
|
+
h > 0 && o.push(n(_));
|
|
311
|
+
throw new globalThis.TypeError(
|
|
312
|
+
`Cycle detected in topological sort. Nodes still pending: ${o.join(", ")}`
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return c;
|
|
316
|
+
}
|
|
317
|
+
const k = -1, m = -1, q = Object.freeze(/* @__PURE__ */ Object.create(null)), ut = 2654435769, ft = 1367130551, K = 1024, j = 0, gt = 31, yt = 1 / 60, mt = 4, pt = 0, R = 20, M = (1 << R) - 1, wt = gt - R, V = (1 << wt) - 1, vt = (a, t) => t << R | a, y = (a) => a & M, z = (a) => a >> R, Et = (a) => F(
|
|
318
|
+
a
|
|
319
|
+
), kt = (a) => F(
|
|
320
|
+
a
|
|
234
321
|
);
|
|
235
|
-
class
|
|
322
|
+
class Tt {
|
|
236
323
|
field_names;
|
|
237
324
|
columns;
|
|
238
325
|
// any: type-erased storage — channel is stored in Map<number, EventChannel>, F is lost
|
|
@@ -263,53 +350,26 @@ class wt {
|
|
|
263
350
|
t[e].length = 0;
|
|
264
351
|
}
|
|
265
352
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
);
|
|
269
|
-
class xt {
|
|
270
|
-
field_names;
|
|
271
|
-
field_index;
|
|
272
|
-
columns;
|
|
273
|
-
// any: type-erased storage — channel is stored in Map<number, ResourceChannel>, F is lost
|
|
274
|
-
reader;
|
|
275
|
-
constructor(t, e) {
|
|
276
|
-
this.field_names = t, this.field_index = /* @__PURE__ */ Object.create(null), this.columns = [];
|
|
277
|
-
for (let r = 0; r < t.length; r++)
|
|
278
|
-
this.field_index[t[r]] = r, this.columns.push([e[t[r]] ?? 0]);
|
|
279
|
-
const s = /* @__PURE__ */ Object.create(null), n = this.columns;
|
|
280
|
-
for (let r = 0; r < t.length; r++) {
|
|
281
|
-
const i = n[r];
|
|
282
|
-
Object.defineProperty(s, t[r], {
|
|
283
|
-
get() {
|
|
284
|
-
return i[R];
|
|
285
|
-
},
|
|
286
|
-
enumerable: !0
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
this.reader = s;
|
|
290
|
-
}
|
|
291
|
-
write(t) {
|
|
292
|
-
const e = this.field_names, s = this.columns;
|
|
293
|
-
for (let n = 0; n < e.length; n++)
|
|
294
|
-
e[n] in t && (s[n][R] = t[e[n]]);
|
|
295
|
-
}
|
|
296
|
-
read_field(t) {
|
|
297
|
-
return this.columns[t][R];
|
|
298
|
-
}
|
|
299
|
-
write_field(t, e) {
|
|
300
|
-
this.columns[t][R] = e;
|
|
301
|
-
}
|
|
353
|
+
function Ot(a) {
|
|
354
|
+
return Symbol(a);
|
|
302
355
|
}
|
|
303
|
-
|
|
304
|
-
|
|
356
|
+
function qt(a) {
|
|
357
|
+
return Symbol(a);
|
|
358
|
+
}
|
|
359
|
+
const bt = (a) => F(
|
|
360
|
+
a
|
|
305
361
|
);
|
|
306
|
-
class
|
|
362
|
+
class At {
|
|
307
363
|
id;
|
|
308
364
|
mask;
|
|
309
365
|
has_columns;
|
|
310
366
|
_entity_ids;
|
|
311
367
|
length = 0;
|
|
312
368
|
edges = [];
|
|
369
|
+
// Cache for multi-component transition maps (from this archetype to another).
|
|
370
|
+
// Covers add_components / remove_components where the (src, dst) pair is not
|
|
371
|
+
// a single-component edge and therefore not covered by `edges[].add_map/remove_map`.
|
|
372
|
+
batch_transition_maps = /* @__PURE__ */ new Map();
|
|
313
373
|
// --- Flat column storage ---
|
|
314
374
|
// Dense array of ALL columns across all components in this archetype.
|
|
315
375
|
_flat_columns = [];
|
|
@@ -325,17 +385,19 @@ class Tt {
|
|
|
325
385
|
column_groups = [];
|
|
326
386
|
// Dense list of ComponentIDs that have columns — used for copy_shared_from.
|
|
327
387
|
_column_ids = [];
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
388
|
+
// Sparse by ComponentID → last tick that modified this component's columns.
|
|
389
|
+
_changed_tick = [];
|
|
390
|
+
constructor(t, e, s, n = K) {
|
|
391
|
+
if (this.id = t, this.mask = e, this._entity_ids = new H(n), s) {
|
|
392
|
+
let i = 0;
|
|
393
|
+
for (let r = 0; r < s.length; r++) {
|
|
394
|
+
const c = s[r], o = c.component_id, _ = new Array(c.field_names.length);
|
|
395
|
+
this._col_offset[o] = i, this._field_count[o] = c.field_names.length, this._field_index[o] = c.field_index, this._field_names[o] = c.field_names;
|
|
396
|
+
for (let h = 0; h < c.field_names.length; h++) {
|
|
397
|
+
const l = new at[c.field_types[h]](n);
|
|
398
|
+
_[h] = l, this._flat_columns[i++] = l;
|
|
337
399
|
}
|
|
338
|
-
this.column_groups[
|
|
400
|
+
this.column_groups[o] = { layout: c, columns: _ }, this._column_ids.push(o), this._changed_tick[o] = 0;
|
|
339
401
|
}
|
|
340
402
|
}
|
|
341
403
|
this.has_columns = this._column_ids.length > 0;
|
|
@@ -356,41 +418,51 @@ class Tt {
|
|
|
356
418
|
matches(t) {
|
|
357
419
|
return this.mask.contains(t);
|
|
358
420
|
}
|
|
359
|
-
/** Get a single field's column. Valid data: indices 0..entity_count-1. */
|
|
421
|
+
/** Get a single field's column (read-only). Valid data: indices 0..entity_count-1. */
|
|
360
422
|
get_column(t, e) {
|
|
361
423
|
const s = t, n = this._field_index[s][e];
|
|
362
424
|
return this._flat_columns[this._col_offset[s] + n].buf;
|
|
363
425
|
}
|
|
364
|
-
|
|
365
|
-
|
|
426
|
+
/** Get a single field's column (mutable). Marks the component as changed at the given tick. */
|
|
427
|
+
get_column_mut(t, e, s) {
|
|
428
|
+
const n = t;
|
|
429
|
+
this._changed_tick[n] = s;
|
|
430
|
+
const i = this._field_index[n][e];
|
|
431
|
+
return this._flat_columns[this._col_offset[n] + i].buf;
|
|
432
|
+
}
|
|
433
|
+
write_fields(t, e, s, n) {
|
|
434
|
+
const i = e, r = this._col_offset[i];
|
|
366
435
|
if (r === void 0) return;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
436
|
+
this._changed_tick[i] = n;
|
|
437
|
+
const c = this._field_names[i], o = this._flat_columns;
|
|
438
|
+
for (let _ = 0; _ < c.length; _++)
|
|
439
|
+
o[r + _].buf[t] = s[c[_]];
|
|
370
440
|
}
|
|
371
441
|
/** Fast positional write: values[i] → field[i] in declaration order. No string lookup. */
|
|
372
|
-
write_fields_positional(t, e, s) {
|
|
373
|
-
const
|
|
442
|
+
write_fields_positional(t, e, s, n) {
|
|
443
|
+
const i = e, r = this._col_offset[i];
|
|
374
444
|
if (r === void 0) return;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
445
|
+
this._changed_tick[i] = n;
|
|
446
|
+
const c = this._flat_columns;
|
|
447
|
+
for (let o = 0; o < s.length; o++)
|
|
448
|
+
c[r + o].buf[t] = s[o];
|
|
378
449
|
}
|
|
379
450
|
read_field(t, e, s) {
|
|
380
|
-
const n = e,
|
|
381
|
-
if (
|
|
382
|
-
const
|
|
383
|
-
return
|
|
451
|
+
const n = e, i = this._col_offset[n];
|
|
452
|
+
if (i === void 0) return NaN;
|
|
453
|
+
const r = this._field_index[n][s];
|
|
454
|
+
return r === void 0 ? NaN : this._flat_columns[i + r].buf[t];
|
|
384
455
|
}
|
|
385
456
|
/** Copy all shared component columns from source archetype at src_row into dst_row. */
|
|
386
|
-
copy_shared_from(t, e, s) {
|
|
387
|
-
const
|
|
388
|
-
for (let
|
|
389
|
-
const
|
|
390
|
-
if (
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
457
|
+
copy_shared_from(t, e, s, n) {
|
|
458
|
+
const i = t._col_offset, r = t._field_count, c = t._flat_columns, o = this._flat_columns, _ = this._column_ids;
|
|
459
|
+
for (let h = 0; h < _.length; h++) {
|
|
460
|
+
const l = _[h], d = i[l];
|
|
461
|
+
if (d === void 0) continue;
|
|
462
|
+
this._changed_tick[l] = n;
|
|
463
|
+
const u = this._col_offset[l], g = r[l];
|
|
464
|
+
for (let w = 0; w < g; w++)
|
|
465
|
+
o[u + w].buf[s] = c[d + w].buf[e];
|
|
394
466
|
}
|
|
395
467
|
}
|
|
396
468
|
/**
|
|
@@ -412,15 +484,15 @@ class Tt {
|
|
|
412
484
|
*/
|
|
413
485
|
remove_entity(t) {
|
|
414
486
|
const e = this.length - 1;
|
|
415
|
-
let s =
|
|
416
|
-
const n = this._flat_columns,
|
|
487
|
+
let s = m;
|
|
488
|
+
const n = this._flat_columns, i = this._entity_ids.buf;
|
|
417
489
|
if (t !== e) {
|
|
418
|
-
|
|
419
|
-
for (let
|
|
420
|
-
n[
|
|
490
|
+
i[t] = i[e], s = y(i[t]);
|
|
491
|
+
for (let r = 0; r < n.length; r++)
|
|
492
|
+
n[r].swap_remove(t);
|
|
421
493
|
} else
|
|
422
|
-
for (let
|
|
423
|
-
n[
|
|
494
|
+
for (let r = 0; r < n.length; r++)
|
|
495
|
+
n[r].pop();
|
|
424
496
|
return this._entity_ids.pop(), this.length--, s;
|
|
425
497
|
}
|
|
426
498
|
/** Tag-optimized add: skip column push entirely (no data to store). */
|
|
@@ -431,9 +503,9 @@ class Tt {
|
|
|
431
503
|
/** Tag-optimized remove via swap-and-pop: skip column swap/pop entirely. */
|
|
432
504
|
remove_entity_tag(t) {
|
|
433
505
|
const e = this.length - 1;
|
|
434
|
-
let s =
|
|
506
|
+
let s = m;
|
|
435
507
|
const n = this._entity_ids.buf;
|
|
436
|
-
return t !== e && (n[t] = n[e], s =
|
|
508
|
+
return t !== e && (n[t] = n[e], s = y(n[t])), this._entity_ids.pop(), this.length--, s;
|
|
437
509
|
}
|
|
438
510
|
/**
|
|
439
511
|
* Move an entity from src archetype into this archetype in a single pass.
|
|
@@ -441,17 +513,20 @@ class Tt {
|
|
|
441
513
|
* Uses a pre-computed transition map for branchless column copy.
|
|
442
514
|
* Writes dst_row to _move_result[0], swapped entity index to _move_result[1].
|
|
443
515
|
*/
|
|
444
|
-
move_entity_from(t, e, s, n) {
|
|
516
|
+
move_entity_from(t, e, s, n, i) {
|
|
445
517
|
const r = this.length;
|
|
446
518
|
this._entity_ids.push(s);
|
|
447
|
-
const
|
|
448
|
-
for (let
|
|
449
|
-
const
|
|
450
|
-
|
|
519
|
+
const c = this._flat_columns, o = t._flat_columns;
|
|
520
|
+
for (let l = 0; l < c.length; l++) {
|
|
521
|
+
const d = n[l];
|
|
522
|
+
c[l].push(d >= 0 ? o[d].buf[e] : 0);
|
|
451
523
|
}
|
|
524
|
+
const _ = this._column_ids;
|
|
525
|
+
for (let l = 0; l < _.length; l++)
|
|
526
|
+
this._changed_tick[_[l]] = i;
|
|
452
527
|
this.length++;
|
|
453
|
-
const
|
|
454
|
-
f[0] = r, f[1] =
|
|
528
|
+
const h = t.has_columns ? t.remove_entity(e) : t.remove_entity_tag(e);
|
|
529
|
+
f[0] = r, f[1] = h;
|
|
455
530
|
}
|
|
456
531
|
/**
|
|
457
532
|
* Move an entity from src into this archetype (tag-only: no columns to copy).
|
|
@@ -460,27 +535,30 @@ class Tt {
|
|
|
460
535
|
move_entity_from_tag(t, e, s) {
|
|
461
536
|
const n = this.length;
|
|
462
537
|
this._entity_ids.push(s), this.length++;
|
|
463
|
-
const
|
|
464
|
-
f[0] = n, f[1] =
|
|
538
|
+
const i = t.remove_entity_tag(e);
|
|
539
|
+
f[0] = n, f[1] = i;
|
|
465
540
|
}
|
|
466
541
|
/**
|
|
467
542
|
* Bulk-move ALL entities from src into this archetype using TypedArray.set().
|
|
468
543
|
* Much faster than per-entity move_entity_from when the entire source is moving.
|
|
469
544
|
* After this call, src is empty. Returns the starting dst_row for the batch.
|
|
470
545
|
*/
|
|
471
|
-
bulk_move_all_from(t, e) {
|
|
472
|
-
const
|
|
473
|
-
if (
|
|
474
|
-
const
|
|
475
|
-
this._entity_ids.bulk_append(t._entity_ids.buf, 0,
|
|
546
|
+
bulk_move_all_from(t, e, s) {
|
|
547
|
+
const n = t.length;
|
|
548
|
+
if (n === 0) return this.length;
|
|
549
|
+
const i = this.length, r = this._flat_columns, c = t._flat_columns;
|
|
550
|
+
this._entity_ids.bulk_append(t._entity_ids.buf, 0, n);
|
|
476
551
|
for (let _ = 0; _ < r.length; _++) {
|
|
477
|
-
const
|
|
478
|
-
|
|
552
|
+
const h = e[_];
|
|
553
|
+
h >= 0 ? r[_].bulk_append(c[h].buf, 0, n) : r[_].bulk_append_zeroes(n);
|
|
479
554
|
}
|
|
480
|
-
|
|
481
|
-
for (let _ = 0; _ <
|
|
482
|
-
|
|
483
|
-
|
|
555
|
+
const o = this._column_ids;
|
|
556
|
+
for (let _ = 0; _ < o.length; _++)
|
|
557
|
+
this._changed_tick[o[_]] = s;
|
|
558
|
+
this.length += n, t.length = 0, t._entity_ids.clear();
|
|
559
|
+
for (let _ = 0; _ < c.length; _++)
|
|
560
|
+
c[_].clear();
|
|
561
|
+
return i;
|
|
484
562
|
}
|
|
485
563
|
get_edge(t) {
|
|
486
564
|
return this.edges[t];
|
|
@@ -488,26 +566,35 @@ class Tt {
|
|
|
488
566
|
set_edge(t, e) {
|
|
489
567
|
this.edges[t] = e;
|
|
490
568
|
}
|
|
569
|
+
/**
|
|
570
|
+
* Get the cached transition map from this archetype to `target`, building
|
|
571
|
+
* and caching it on miss. Archetypes live for the lifetime of the Store,
|
|
572
|
+
* so entries never need invalidation.
|
|
573
|
+
*/
|
|
574
|
+
get_batch_transition_map(t) {
|
|
575
|
+
let e = this.batch_transition_maps.get(t.id);
|
|
576
|
+
return e === void 0 && (e = G(this, t), this.batch_transition_maps.set(t.id, e)), e;
|
|
577
|
+
}
|
|
491
578
|
}
|
|
492
|
-
const f = [0,
|
|
493
|
-
function
|
|
494
|
-
const e = t._flat_columns, s = new Int16Array(e.length), n = t._column_ids,
|
|
495
|
-
for (let
|
|
496
|
-
const
|
|
497
|
-
if (
|
|
498
|
-
for (let
|
|
499
|
-
s[h +
|
|
579
|
+
const f = [0, m];
|
|
580
|
+
function G(a, t) {
|
|
581
|
+
const e = t._flat_columns, s = new Int16Array(e.length), n = t._column_ids, i = a._col_offset, r = t._col_offset, c = t._field_count;
|
|
582
|
+
for (let o = 0; o < n.length; o++) {
|
|
583
|
+
const _ = n[o], h = r[_], l = c[_], d = i[_];
|
|
584
|
+
if (d !== void 0)
|
|
585
|
+
for (let u = 0; u < l; u++)
|
|
586
|
+
s[h + u] = d + u;
|
|
500
587
|
else
|
|
501
|
-
for (let
|
|
502
|
-
s[h +
|
|
588
|
+
for (let u = 0; u < l; u++)
|
|
589
|
+
s[h + u] = -1;
|
|
503
590
|
}
|
|
504
591
|
return s;
|
|
505
592
|
}
|
|
506
|
-
function
|
|
507
|
-
const s =
|
|
508
|
-
s !== void 0 ? s.push(e) :
|
|
593
|
+
function Q(a, t, e) {
|
|
594
|
+
const s = a.get(t);
|
|
595
|
+
s !== void 0 ? s.push(e) : a.set(t, [e]);
|
|
509
596
|
}
|
|
510
|
-
class
|
|
597
|
+
class xt {
|
|
511
598
|
// --- Entity ID management ---
|
|
512
599
|
// Generational slot allocator: entity_generations[index] holds the current
|
|
513
600
|
// generation for that slot. Free indices are recycled via a stack.
|
|
@@ -524,10 +611,6 @@ class At {
|
|
|
524
611
|
// Parallel array indexed by EventID: each channel holds SoA columns + reader.
|
|
525
612
|
event_channels = [];
|
|
526
613
|
event_count = 0;
|
|
527
|
-
// --- Resource channels ---
|
|
528
|
-
// Parallel array indexed by ResourceID: each channel holds a single row of SoA columns.
|
|
529
|
-
resource_channels = [];
|
|
530
|
-
resource_count = 0;
|
|
531
614
|
// --- Archetype management ---
|
|
532
615
|
archetypes = [];
|
|
533
616
|
// Hash-bucketed lookup: BitSet.hash() → ArchetypeID[] for deduplication
|
|
@@ -553,9 +636,10 @@ class At {
|
|
|
553
636
|
pending_add_values = [];
|
|
554
637
|
pending_remove_ids = [];
|
|
555
638
|
pending_remove_defs = [];
|
|
639
|
+
_tick = 0;
|
|
556
640
|
initial_capacity;
|
|
557
641
|
constructor(t) {
|
|
558
|
-
this.initial_capacity = t ??
|
|
642
|
+
this.initial_capacity = t ?? K, this.empty_archetype_id = this.arch_get_or_create_from_mask(new p());
|
|
559
643
|
}
|
|
560
644
|
// =======================================================
|
|
561
645
|
// Archetype graph
|
|
@@ -570,30 +654,30 @@ class At {
|
|
|
570
654
|
arch_get_or_create_from_mask(t) {
|
|
571
655
|
const e = t.hash(), s = this.archetype_map.get(e);
|
|
572
656
|
if (s !== void 0) {
|
|
573
|
-
for (let
|
|
574
|
-
if (this.archetypes[s[
|
|
575
|
-
return s[
|
|
657
|
+
for (let o = 0; o < s.length; o++)
|
|
658
|
+
if (this.archetypes[s[o]].mask.equals(t))
|
|
659
|
+
return s[o];
|
|
576
660
|
}
|
|
577
|
-
const n = bt(this.next_archetype_id++),
|
|
578
|
-
t.for_each((
|
|
579
|
-
const
|
|
580
|
-
h && h.field_names.length > 0 &&
|
|
581
|
-
component_id:
|
|
661
|
+
const n = bt(this.next_archetype_id++), i = [];
|
|
662
|
+
t.for_each((o) => {
|
|
663
|
+
const _ = o, h = this.component_metas[_];
|
|
664
|
+
h && h.field_names.length > 0 && i.push({
|
|
665
|
+
component_id: _,
|
|
582
666
|
field_names: h.field_names,
|
|
583
667
|
field_index: h.field_index,
|
|
584
668
|
field_types: h.field_types
|
|
585
669
|
});
|
|
586
670
|
});
|
|
587
|
-
const
|
|
588
|
-
this.archetypes.push(
|
|
589
|
-
const
|
|
590
|
-
let h = this.component_index.get(
|
|
591
|
-
h || (h = /* @__PURE__ */ new Set(), this.component_index.set(
|
|
671
|
+
const r = new At(n, t, i, this.initial_capacity);
|
|
672
|
+
this.archetypes.push(r), Q(this.archetype_map, e, n), t.for_each((o) => {
|
|
673
|
+
const _ = o;
|
|
674
|
+
let h = this.component_index.get(_);
|
|
675
|
+
h || (h = /* @__PURE__ */ new Set(), this.component_index.set(_, h)), h.add(n);
|
|
592
676
|
});
|
|
593
|
-
const
|
|
594
|
-
for (let
|
|
595
|
-
const
|
|
596
|
-
|
|
677
|
+
const c = this.registered_queries;
|
|
678
|
+
for (let o = 0; o < c.length; o++) {
|
|
679
|
+
const _ = c[o];
|
|
680
|
+
r.matches(_.include_mask) && (!_.exclude_mask || !r.mask.overlaps(_.exclude_mask)) && (!_.any_of_mask || r.mask.overlaps(_.any_of_mask)) && (_.result.push(r), _.query?.mark_non_empty_dirty());
|
|
597
681
|
}
|
|
598
682
|
return n;
|
|
599
683
|
}
|
|
@@ -603,10 +687,10 @@ class At {
|
|
|
603
687
|
if (s.mask.has(e)) return t;
|
|
604
688
|
const n = s.get_edge(e);
|
|
605
689
|
if (n?.add != null) return n.add;
|
|
606
|
-
const
|
|
690
|
+
const i = this.arch_get_or_create_from_mask(
|
|
607
691
|
s.mask.copy_with_set(e)
|
|
608
692
|
);
|
|
609
|
-
return this.arch_cache_edge(s, this.arch_get(
|
|
693
|
+
return this.arch_cache_edge(s, this.arch_get(i), e), i;
|
|
610
694
|
}
|
|
611
695
|
/** Resolve "remove component_id from archetype_id" → target ArchetypeID. Caches the edge. */
|
|
612
696
|
arch_resolve_remove(t, e) {
|
|
@@ -614,10 +698,10 @@ class At {
|
|
|
614
698
|
if (!s.mask.has(e)) return t;
|
|
615
699
|
const n = s.get_edge(e);
|
|
616
700
|
if (n?.remove != null) return n.remove;
|
|
617
|
-
const
|
|
701
|
+
const i = this.arch_get_or_create_from_mask(
|
|
618
702
|
s.mask.copy_with_clear(e)
|
|
619
703
|
);
|
|
620
|
-
return this.arch_cache_edge(this.arch_get(
|
|
704
|
+
return this.arch_cache_edge(this.arch_get(i), s, e), i;
|
|
621
705
|
}
|
|
622
706
|
/** Cache a bidirectional add/remove edge between two archetypes. */
|
|
623
707
|
arch_cache_edge(t, e, s) {
|
|
@@ -627,14 +711,14 @@ class At {
|
|
|
627
711
|
add_map: null,
|
|
628
712
|
remove_map: null
|
|
629
713
|
};
|
|
630
|
-
n.add = e.id, n.add_map =
|
|
631
|
-
const
|
|
714
|
+
n.add = e.id, n.add_map = G(t, e), t.set_edge(s, n);
|
|
715
|
+
const i = e.get_edge(s) ?? {
|
|
632
716
|
add: null,
|
|
633
717
|
remove: null,
|
|
634
718
|
add_map: null,
|
|
635
719
|
remove_map: null
|
|
636
720
|
};
|
|
637
|
-
|
|
721
|
+
i.remove = t.id, i.remove_map = G(e, t), e.set_edge(s, i);
|
|
638
722
|
}
|
|
639
723
|
// =======================================================
|
|
640
724
|
// Entity lifecycle
|
|
@@ -642,29 +726,34 @@ class At {
|
|
|
642
726
|
create_entity() {
|
|
643
727
|
let t, e;
|
|
644
728
|
this.entity_free_indices.length > 0 ? (t = this.entity_free_indices.pop(), e = this.entity_generations[t]) : (t = this.entity_high_water++, this.entity_generations[t] = j, e = j), this.entity_alive_count++;
|
|
645
|
-
const s =
|
|
646
|
-
return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] =
|
|
729
|
+
const s = vt(t, e);
|
|
730
|
+
return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] = k, s;
|
|
647
731
|
}
|
|
648
732
|
/** Immediately destroy an entity, removing it from its archetype. */
|
|
649
733
|
destroy_entity(t) {
|
|
650
734
|
if (!this.is_alive(t))
|
|
651
735
|
return;
|
|
652
|
-
const e =
|
|
653
|
-
if (s !==
|
|
654
|
-
const
|
|
655
|
-
|
|
736
|
+
const e = y(t), s = this.entity_row[e];
|
|
737
|
+
if (s !== k) {
|
|
738
|
+
const r = this.arch_get(this.entity_archetype[e]).remove_entity(s);
|
|
739
|
+
r !== m && (this.entity_row[r] = s);
|
|
656
740
|
}
|
|
657
|
-
this.entity_archetype[e] =
|
|
658
|
-
const n =
|
|
659
|
-
this.entity_generations[e] = n + 1 &
|
|
741
|
+
this.entity_archetype[e] = k, this.entity_row[e] = k;
|
|
742
|
+
const n = z(t);
|
|
743
|
+
this.entity_generations[e] = n + 1 & V, this.entity_free_indices.push(e), this.entity_alive_count--;
|
|
660
744
|
}
|
|
661
745
|
is_alive(t) {
|
|
662
|
-
const e =
|
|
663
|
-
return e < this.entity_high_water && this.entity_generations[e] ===
|
|
746
|
+
const e = y(t);
|
|
747
|
+
return e < this.entity_high_water && this.entity_generations[e] === z(t);
|
|
664
748
|
}
|
|
665
749
|
get entity_count() {
|
|
666
750
|
return this.entity_alive_count;
|
|
667
751
|
}
|
|
752
|
+
_mark_queries_dirty() {
|
|
753
|
+
const t = this.registered_queries;
|
|
754
|
+
for (let e = 0; e < t.length; e++)
|
|
755
|
+
t[e].query?.mark_non_empty_dirty();
|
|
756
|
+
}
|
|
668
757
|
// =======================================================
|
|
669
758
|
// Deferred destruction
|
|
670
759
|
// =======================================================
|
|
@@ -675,74 +764,75 @@ class At {
|
|
|
675
764
|
flush_destroyed() {
|
|
676
765
|
const t = this.pending_destroy;
|
|
677
766
|
if (t.length === 0) return;
|
|
678
|
-
const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations,
|
|
679
|
-
for (let
|
|
680
|
-
const
|
|
681
|
-
if (
|
|
682
|
-
const
|
|
683
|
-
if (
|
|
684
|
-
const
|
|
685
|
-
|
|
767
|
+
const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, i = this.archetypes, r = this.entity_high_water;
|
|
768
|
+
for (let c = 0; c < t.length; c++) {
|
|
769
|
+
const o = t[c], _ = o & M, h = o >> R;
|
|
770
|
+
if (_ >= r || n[_] !== h) continue;
|
|
771
|
+
const l = s[_];
|
|
772
|
+
if (l !== k) {
|
|
773
|
+
const d = i[e[_]], u = d.has_columns ? d.remove_entity(l) : d.remove_entity_tag(l);
|
|
774
|
+
u !== m && (s[u] = l);
|
|
686
775
|
}
|
|
687
|
-
e[
|
|
776
|
+
e[_] = k, s[_] = k, n[_] = h + 1 & V, this.entity_free_indices.push(_), this.entity_alive_count--;
|
|
688
777
|
}
|
|
689
|
-
t.length = 0;
|
|
778
|
+
t.length = 0, this._mark_queries_dirty();
|
|
690
779
|
}
|
|
691
780
|
get pending_destroy_count() {
|
|
692
781
|
return this.pending_destroy.length;
|
|
693
782
|
}
|
|
694
783
|
add_component_deferred(t, e, s) {
|
|
695
|
-
this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ??
|
|
784
|
+
this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? q);
|
|
696
785
|
}
|
|
697
786
|
remove_component_deferred(t, e) {
|
|
698
787
|
this.pending_remove_ids.push(t), this.pending_remove_defs.push(e);
|
|
699
788
|
}
|
|
700
789
|
flush_structural() {
|
|
701
|
-
this.pending_add_ids.length > 0
|
|
790
|
+
const t = this.pending_add_ids.length > 0, e = this.pending_remove_ids.length > 0;
|
|
791
|
+
t && this._flush_adds(), e && this._flush_removes(), (t || e) && this._mark_queries_dirty();
|
|
702
792
|
}
|
|
703
793
|
/** Batch-apply all deferred component additions. */
|
|
704
794
|
_flush_adds() {
|
|
705
|
-
const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length,
|
|
706
|
-
for (let
|
|
707
|
-
const u = t[
|
|
708
|
-
if (
|
|
709
|
-
const T =
|
|
710
|
-
if (
|
|
711
|
-
|
|
795
|
+
const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length, i = this.entity_archetype, r = this.entity_row, c = this.entity_generations, o = this.archetypes, _ = this.component_metas, h = this.entity_high_water, l = this._tick;
|
|
796
|
+
for (let d = 0; d < n; d++) {
|
|
797
|
+
const u = t[d], g = u & M, w = u >> R;
|
|
798
|
+
if (g >= h || c[g] !== w) continue;
|
|
799
|
+
const T = i[g], v = e[d], E = o[T];
|
|
800
|
+
if (E.mask.has(v)) {
|
|
801
|
+
_[v].field_names.length > 0 && E.write_fields(r[g], v, s[d], l);
|
|
712
802
|
continue;
|
|
713
803
|
}
|
|
714
|
-
const
|
|
804
|
+
const N = this.arch_resolve_add(T, v), x = o[N], P = r[g], Y = !x.has_columns && !E.has_columns;
|
|
715
805
|
let U;
|
|
716
|
-
if (
|
|
717
|
-
if (
|
|
718
|
-
|
|
806
|
+
if (P !== k) {
|
|
807
|
+
if (Y)
|
|
808
|
+
x.move_entity_from_tag(E, P, u);
|
|
719
809
|
else {
|
|
720
|
-
const
|
|
721
|
-
|
|
810
|
+
const J = E.get_edge(v);
|
|
811
|
+
x.move_entity_from(E, P, u, J.add_map, l);
|
|
722
812
|
}
|
|
723
|
-
U = f[0], f[1] !==
|
|
813
|
+
U = f[0], f[1] !== m && (r[f[1]] = P);
|
|
724
814
|
} else
|
|
725
|
-
U =
|
|
726
|
-
|
|
815
|
+
U = Y ? x.add_entity_tag(u) : x.add_entity(u);
|
|
816
|
+
_[v].field_names.length > 0 && x.write_fields(U, v, s[d], l), i[g] = N, r[g] = U;
|
|
727
817
|
}
|
|
728
818
|
t.length = 0, e.length = 0, s.length = 0;
|
|
729
819
|
}
|
|
730
820
|
/** Batch-apply all deferred component removals. */
|
|
731
821
|
_flush_removes() {
|
|
732
|
-
const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype,
|
|
733
|
-
for (let
|
|
734
|
-
const
|
|
735
|
-
if (
|
|
736
|
-
const
|
|
737
|
-
if (!T.mask.has(
|
|
738
|
-
const
|
|
739
|
-
if (!
|
|
740
|
-
|
|
822
|
+
const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype, i = this.entity_row, r = this.entity_generations, c = this.archetypes, o = this.entity_high_water, _ = this._tick;
|
|
823
|
+
for (let h = 0; h < s; h++) {
|
|
824
|
+
const l = t[h], d = l & M, u = l >> R;
|
|
825
|
+
if (d >= o || r[d] !== u) continue;
|
|
826
|
+
const g = n[d], w = e[h], T = c[g];
|
|
827
|
+
if (!T.mask.has(w)) continue;
|
|
828
|
+
const v = this.arch_resolve_remove(g, w), E = c[v], N = i[d];
|
|
829
|
+
if (!E.has_columns && !T.has_columns)
|
|
830
|
+
E.move_entity_from_tag(T, N, l);
|
|
741
831
|
else {
|
|
742
|
-
const
|
|
743
|
-
|
|
832
|
+
const P = T.get_edge(w);
|
|
833
|
+
E.move_entity_from(T, N, l, P.remove_map, _);
|
|
744
834
|
}
|
|
745
|
-
f[1] !==
|
|
835
|
+
f[1] !== m && (i[f[1]] = N), n[d] = v, i[d] = f[0];
|
|
746
836
|
}
|
|
747
837
|
t.length = 0, e.length = 0;
|
|
748
838
|
}
|
|
@@ -753,108 +843,101 @@ class At {
|
|
|
753
843
|
// Component registration
|
|
754
844
|
// =======================================================
|
|
755
845
|
register_component(t) {
|
|
756
|
-
const e =
|
|
757
|
-
for (let
|
|
758
|
-
|
|
759
|
-
return this.component_metas.push({ field_names: s, field_index:
|
|
846
|
+
const e = Et(this.component_count++), s = Object.keys(t), n = new Array(s.length), i = /* @__PURE__ */ Object.create(null);
|
|
847
|
+
for (let r = 0; r < s.length; r++)
|
|
848
|
+
i[s[r]] = r, n[r] = t[s[r]];
|
|
849
|
+
return this.component_metas.push({ field_names: s, field_index: i, field_types: n }), e;
|
|
760
850
|
}
|
|
761
851
|
add_component(t, e, s) {
|
|
762
852
|
if (!this.is_alive(t))
|
|
763
853
|
return;
|
|
764
|
-
const n =
|
|
765
|
-
if (
|
|
766
|
-
|
|
854
|
+
const n = y(t), i = this.entity_archetype[n], r = this.arch_get(i);
|
|
855
|
+
if (r.has_component(e)) {
|
|
856
|
+
r.write_fields(
|
|
767
857
|
this.entity_row[n],
|
|
768
858
|
e,
|
|
769
|
-
s
|
|
859
|
+
s,
|
|
860
|
+
this._tick
|
|
770
861
|
);
|
|
771
862
|
return;
|
|
772
863
|
}
|
|
773
|
-
const
|
|
774
|
-
r,
|
|
775
|
-
e
|
|
776
|
-
), c = this.arch_get(_), o = this.entity_row[n];
|
|
864
|
+
const c = this.arch_resolve_add(i, e), o = this.arch_get(c), _ = this.entity_row[n];
|
|
777
865
|
let h;
|
|
778
|
-
if (
|
|
779
|
-
const
|
|
780
|
-
!
|
|
866
|
+
if (_ !== k) {
|
|
867
|
+
const l = r.get_edge(e);
|
|
868
|
+
!o.has_columns && !r.has_columns ? o.move_entity_from_tag(r, _, t) : o.move_entity_from(r, _, t, l.add_map, this._tick), h = f[0], f[1] !== m && (this.entity_row[f[1]] = _);
|
|
781
869
|
} else
|
|
782
|
-
h =
|
|
783
|
-
|
|
870
|
+
h = o.has_columns ? o.add_entity(t) : o.add_entity_tag(t);
|
|
871
|
+
o.write_fields(
|
|
784
872
|
h,
|
|
785
873
|
e,
|
|
786
|
-
s
|
|
787
|
-
|
|
874
|
+
s,
|
|
875
|
+
this._tick
|
|
876
|
+
), this.entity_archetype[n] = c, this.entity_row[n] = h, this._mark_queries_dirty();
|
|
788
877
|
}
|
|
789
878
|
/** Add multiple components in one transition (resolves final archetype, then moves once). */
|
|
790
879
|
add_components(t, e) {
|
|
791
880
|
if (!this.is_alive(t))
|
|
792
881
|
return;
|
|
793
|
-
const s =
|
|
794
|
-
let
|
|
795
|
-
for (let
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (c !== v) {
|
|
804
|
-
const h = M(i, _);
|
|
805
|
-
_.move_entity_from(i, c, t, h), o = f[0], f[1] !== y && (this.entity_row[f[1]] = c);
|
|
882
|
+
const s = y(t), n = this.entity_archetype[s];
|
|
883
|
+
let i = n;
|
|
884
|
+
for (let r = 0; r < e.length; r++)
|
|
885
|
+
i = this.arch_resolve_add(i, e[r].def);
|
|
886
|
+
if (i !== n) {
|
|
887
|
+
const r = this.arch_get(n), c = this.arch_get(i), o = this.entity_row[s];
|
|
888
|
+
let _;
|
|
889
|
+
if (o !== k) {
|
|
890
|
+
const h = r.get_batch_transition_map(c);
|
|
891
|
+
c.move_entity_from(r, o, t, h, this._tick), _ = f[0], f[1] !== m && (this.entity_row[f[1]] = o);
|
|
806
892
|
} else
|
|
807
|
-
|
|
893
|
+
_ = c.add_entity(t);
|
|
808
894
|
for (let h = 0; h < e.length; h++)
|
|
809
|
-
|
|
810
|
-
|
|
895
|
+
c.write_fields(
|
|
896
|
+
_,
|
|
811
897
|
e[h].def,
|
|
812
|
-
e[h].values ??
|
|
898
|
+
e[h].values ?? q,
|
|
899
|
+
this._tick
|
|
813
900
|
);
|
|
814
|
-
this.entity_archetype[s] =
|
|
901
|
+
this.entity_archetype[s] = i, this.entity_row[s] = _, this._mark_queries_dirty();
|
|
815
902
|
} else {
|
|
816
|
-
const
|
|
817
|
-
for (let
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
e[
|
|
821
|
-
e[
|
|
903
|
+
const r = this.arch_get(n), c = this.entity_row[s];
|
|
904
|
+
for (let o = 0; o < e.length; o++)
|
|
905
|
+
r.write_fields(
|
|
906
|
+
c,
|
|
907
|
+
e[o].def,
|
|
908
|
+
e[o].values ?? q,
|
|
909
|
+
this._tick
|
|
822
910
|
);
|
|
823
911
|
}
|
|
824
912
|
}
|
|
825
913
|
remove_component(t, e) {
|
|
826
914
|
if (!this.is_alive(t))
|
|
827
915
|
return;
|
|
828
|
-
const s =
|
|
829
|
-
if (!
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
e
|
|
833
|
-
), _ = this.arch_get(i), c = this.entity_row[s], o = r.get_edge(e);
|
|
834
|
-
!_.has_columns && !r.has_columns ? _.move_entity_from_tag(r, c, t) : _.move_entity_from(r, c, t, o.remove_map), f[1] !== y && (this.entity_row[f[1]] = c), this.entity_archetype[s] = i, this.entity_row[s] = f[0];
|
|
916
|
+
const s = y(t), n = this.entity_archetype[s], i = this.arch_get(n);
|
|
917
|
+
if (!i.has_component(e)) return;
|
|
918
|
+
const r = this.arch_resolve_remove(n, e), c = this.arch_get(r), o = this.entity_row[s], _ = i.get_edge(e);
|
|
919
|
+
!c.has_columns && !i.has_columns ? c.move_entity_from_tag(i, o, t) : c.move_entity_from(i, o, t, _.remove_map, this._tick), f[1] !== m && (this.entity_row[f[1]] = o), this.entity_archetype[s] = r, this.entity_row[s] = f[0], this._mark_queries_dirty();
|
|
835
920
|
}
|
|
836
921
|
/** Remove multiple components in one transition (resolves final archetype, then moves once). */
|
|
837
922
|
remove_components(t, e) {
|
|
838
923
|
if (!this.is_alive(t))
|
|
839
924
|
return;
|
|
840
|
-
const s =
|
|
841
|
-
let
|
|
925
|
+
const s = y(t), n = this.entity_archetype[s];
|
|
926
|
+
let i = n;
|
|
842
927
|
for (let h = 0; h < e.length; h++)
|
|
843
|
-
|
|
844
|
-
|
|
928
|
+
i = this.arch_resolve_remove(
|
|
929
|
+
i,
|
|
845
930
|
e[h]
|
|
846
931
|
);
|
|
847
|
-
if (
|
|
848
|
-
const
|
|
849
|
-
|
|
932
|
+
if (i === n) return;
|
|
933
|
+
const r = this.arch_get(n), c = this.arch_get(i), o = this.entity_row[s], _ = G(r, c);
|
|
934
|
+
c.move_entity_from(r, o, t, _, this._tick), f[1] !== m && (this.entity_row[f[1]] = o), this.entity_archetype[s] = i, this.entity_row[s] = f[0], this._mark_queries_dirty();
|
|
850
935
|
}
|
|
851
936
|
has_component(t, e) {
|
|
852
937
|
if (!this.is_alive(t))
|
|
853
938
|
return !1;
|
|
854
|
-
const s =
|
|
855
|
-
return this.arch_get(
|
|
856
|
-
this.entity_archetype[s]
|
|
857
|
-
).has_component(e);
|
|
939
|
+
const s = y(t);
|
|
940
|
+
return this.arch_get(this.entity_archetype[s]).has_component(e);
|
|
858
941
|
}
|
|
859
942
|
/**
|
|
860
943
|
* Bulk add a component to ALL entities in the given archetype.
|
|
@@ -865,14 +948,15 @@ class At {
|
|
|
865
948
|
if (t.length === 0) return;
|
|
866
949
|
const n = e;
|
|
867
950
|
if (t.mask.has(n)) return;
|
|
868
|
-
const
|
|
869
|
-
for (let
|
|
870
|
-
const g =
|
|
871
|
-
|
|
951
|
+
const i = this.arch_resolve_add(t.id, n), r = this.arch_get(i), c = t.get_edge(n), o = t.length, _ = this.entity_archetype, h = this.entity_row, l = r.bulk_move_all_from(t, c.add_map, this._tick);
|
|
952
|
+
for (let u = 0; u < o; u++) {
|
|
953
|
+
const g = y(r.entity_ids[l + u]);
|
|
954
|
+
_[g] = i, h[g] = l + u;
|
|
872
955
|
}
|
|
873
956
|
if (this.component_metas[n].field_names.length > 0 && s)
|
|
874
|
-
for (let
|
|
875
|
-
|
|
957
|
+
for (let u = 0; u < o; u++)
|
|
958
|
+
r.write_fields(l + u, n, s, this._tick);
|
|
959
|
+
this._mark_queries_dirty();
|
|
876
960
|
}
|
|
877
961
|
/**
|
|
878
962
|
* Bulk remove a component from ALL entities in the given archetype.
|
|
@@ -883,22 +967,21 @@ class At {
|
|
|
883
967
|
if (t.length === 0) return;
|
|
884
968
|
const s = e;
|
|
885
969
|
if (!t.mask.has(s)) return;
|
|
886
|
-
const n = this.arch_resolve_remove(t.id, s),
|
|
887
|
-
for (let
|
|
888
|
-
const
|
|
889
|
-
|
|
970
|
+
const n = this.arch_resolve_remove(t.id, s), i = this.arch_get(n), r = t.get_edge(s), c = t.length, o = i.bulk_move_all_from(t, r.remove_map, this._tick), _ = this.entity_archetype, h = this.entity_row;
|
|
971
|
+
for (let l = 0; l < c; l++) {
|
|
972
|
+
const d = y(i.entity_ids[o + l]);
|
|
973
|
+
_[d] = n, h[d] = o + l;
|
|
890
974
|
}
|
|
975
|
+
this._mark_queries_dirty();
|
|
891
976
|
}
|
|
892
977
|
// =======================================================
|
|
893
978
|
// Direct data access (used by SystemContext)
|
|
894
979
|
// =======================================================
|
|
895
980
|
get_entity_archetype(t) {
|
|
896
|
-
return this.arch_get(
|
|
897
|
-
this.entity_archetype[m(t)]
|
|
898
|
-
);
|
|
981
|
+
return this.arch_get(this.entity_archetype[y(t)]);
|
|
899
982
|
}
|
|
900
983
|
get_entity_row(t) {
|
|
901
|
-
return this.entity_row[
|
|
984
|
+
return this.entity_row[y(t)];
|
|
902
985
|
}
|
|
903
986
|
// =======================================================
|
|
904
987
|
// Query support
|
|
@@ -910,58 +993,63 @@ class At {
|
|
|
910
993
|
*/
|
|
911
994
|
get_matching_archetypes(t, e, s) {
|
|
912
995
|
const n = t._words;
|
|
913
|
-
let
|
|
914
|
-
for (let
|
|
915
|
-
if (n[
|
|
916
|
-
|
|
996
|
+
let i = !1;
|
|
997
|
+
for (let _ = 0; _ < n.length; _++)
|
|
998
|
+
if (n[_] !== 0) {
|
|
999
|
+
i = !0;
|
|
917
1000
|
break;
|
|
918
1001
|
}
|
|
919
|
-
if (!
|
|
1002
|
+
if (!i)
|
|
920
1003
|
return this.archetypes.filter(
|
|
921
|
-
(
|
|
1004
|
+
(_) => (!e || !_.mask.overlaps(e)) && (!s || _.mask.overlaps(s))
|
|
922
1005
|
);
|
|
923
|
-
let
|
|
924
|
-
for (let
|
|
925
|
-
let h = n[
|
|
1006
|
+
let r, c = !1;
|
|
1007
|
+
for (let _ = 0; _ < n.length; _++) {
|
|
1008
|
+
let h = n[_];
|
|
926
1009
|
if (h === 0) continue;
|
|
927
|
-
const
|
|
1010
|
+
const l = _ << I;
|
|
928
1011
|
for (; h !== 0; ) {
|
|
929
|
-
const
|
|
930
|
-
h ^=
|
|
931
|
-
const g = this.component_index.get(
|
|
1012
|
+
const d = h & -h >>> 0, u = l + (S - Math.clz32(d));
|
|
1013
|
+
h ^= d;
|
|
1014
|
+
const g = this.component_index.get(u);
|
|
932
1015
|
if (!g || g.size === 0) {
|
|
933
|
-
|
|
1016
|
+
c = !0;
|
|
934
1017
|
break;
|
|
935
1018
|
}
|
|
936
|
-
(!
|
|
1019
|
+
(!r || g.size < r.size) && (r = g);
|
|
937
1020
|
}
|
|
938
|
-
if (
|
|
1021
|
+
if (c) break;
|
|
939
1022
|
}
|
|
940
|
-
if (
|
|
941
|
-
const
|
|
942
|
-
for (const
|
|
943
|
-
const h = this.arch_get(
|
|
944
|
-
h.matches(t) && (!e || !h.mask.overlaps(e)) && (!s || h.mask.overlaps(s)) &&
|
|
1023
|
+
if (c || !r) return [];
|
|
1024
|
+
const o = [];
|
|
1025
|
+
for (const _ of r) {
|
|
1026
|
+
const h = this.arch_get(_);
|
|
1027
|
+
h.matches(t) && (!e || !h.mask.overlaps(e)) && (!s || h.mask.overlaps(s)) && o.push(h);
|
|
945
1028
|
}
|
|
946
|
-
return
|
|
1029
|
+
return o;
|
|
947
1030
|
}
|
|
948
1031
|
/**
|
|
949
1032
|
* Register a live query. Returns a mutable Archetype[] that this Store will
|
|
950
1033
|
* push newly-created matching archetypes into, keeping the query always up-to-date.
|
|
951
1034
|
*/
|
|
952
1035
|
register_query(t, e, s) {
|
|
953
|
-
const n = this.get_matching_archetypes(
|
|
954
|
-
t,
|
|
955
|
-
e,
|
|
956
|
-
s
|
|
957
|
-
);
|
|
1036
|
+
const n = this.get_matching_archetypes(t, e, s);
|
|
958
1037
|
return this.registered_queries.push({
|
|
959
1038
|
include_mask: t.copy(),
|
|
960
1039
|
exclude_mask: e ? e.copy() : null,
|
|
961
1040
|
any_of_mask: s ? s.copy() : null,
|
|
962
|
-
result: n
|
|
1041
|
+
result: n,
|
|
1042
|
+
query: null
|
|
963
1043
|
}), n;
|
|
964
1044
|
}
|
|
1045
|
+
update_query_ref(t, e) {
|
|
1046
|
+
const s = this.registered_queries;
|
|
1047
|
+
for (let n = 0; n < s.length; n++)
|
|
1048
|
+
if (s[n].result === t) {
|
|
1049
|
+
s[n].query = e;
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
965
1053
|
get archetype_count() {
|
|
966
1054
|
return this.archetypes.length;
|
|
967
1055
|
}
|
|
@@ -969,7 +1057,7 @@ class At {
|
|
|
969
1057
|
// Event channels
|
|
970
1058
|
// =======================================================
|
|
971
1059
|
register_event(t) {
|
|
972
|
-
const e =
|
|
1060
|
+
const e = kt(this.event_count++), s = new Tt(t);
|
|
973
1061
|
return this.event_channels.push(s), e;
|
|
974
1062
|
}
|
|
975
1063
|
emit_event(t, e) {
|
|
@@ -987,76 +1075,107 @@ class At {
|
|
|
987
1075
|
t[e].clear();
|
|
988
1076
|
}
|
|
989
1077
|
// =======================================================
|
|
990
|
-
//
|
|
1078
|
+
// Event key storage
|
|
1079
|
+
// =======================================================
|
|
1080
|
+
// any: type-erased — EventDef<F> phantom is lost in the map, recovered by callers via EventKey<F>
|
|
1081
|
+
event_key_map = /* @__PURE__ */ new Map();
|
|
1082
|
+
register_event_by_key(t, e) {
|
|
1083
|
+
if (this.event_key_map.has(t))
|
|
1084
|
+
throw new O(D.EVENT_ALREADY_REGISTERED, "Event key already registered");
|
|
1085
|
+
const s = this.register_event(e);
|
|
1086
|
+
return this.event_key_map.set(t, s), s;
|
|
1087
|
+
}
|
|
1088
|
+
// any: type-erased — caller recovers F from EventKey<F>
|
|
1089
|
+
get_event_def_by_key(t) {
|
|
1090
|
+
const e = this.event_key_map.get(t);
|
|
1091
|
+
if (e === void 0)
|
|
1092
|
+
throw new O(D.EVENT_NOT_REGISTERED, "Event key not registered");
|
|
1093
|
+
return e;
|
|
1094
|
+
}
|
|
1095
|
+
has_event_key(t) {
|
|
1096
|
+
return this.event_key_map.has(t);
|
|
1097
|
+
}
|
|
1098
|
+
// =======================================================
|
|
1099
|
+
// Resource storage
|
|
991
1100
|
// =======================================================
|
|
1101
|
+
resource_key_map = /* @__PURE__ */ new Map();
|
|
992
1102
|
register_resource(t, e) {
|
|
993
|
-
|
|
994
|
-
|
|
1103
|
+
if (this.resource_key_map.has(t))
|
|
1104
|
+
throw new O(D.RESOURCE_ALREADY_REGISTERED, "Resource key already registered");
|
|
1105
|
+
this.resource_key_map.set(t, e);
|
|
995
1106
|
}
|
|
996
|
-
|
|
997
|
-
|
|
1107
|
+
get_resource(t) {
|
|
1108
|
+
if (!this.resource_key_map.has(t))
|
|
1109
|
+
throw new O(D.RESOURCE_NOT_REGISTERED, "Resource key not registered");
|
|
1110
|
+
return this.resource_key_map.get(t);
|
|
1111
|
+
}
|
|
1112
|
+
set_resource(t, e) {
|
|
1113
|
+
if (!this.resource_key_map.has(t))
|
|
1114
|
+
throw new O(D.RESOURCE_NOT_REGISTERED, "Resource key not registered");
|
|
1115
|
+
this.resource_key_map.set(t, e);
|
|
998
1116
|
}
|
|
999
|
-
|
|
1000
|
-
return this.
|
|
1117
|
+
has_resource(t) {
|
|
1118
|
+
return this.resource_key_map.has(t);
|
|
1001
1119
|
}
|
|
1002
1120
|
}
|
|
1003
|
-
var
|
|
1004
|
-
const
|
|
1121
|
+
var It = /* @__PURE__ */ ((a) => (a.PRE_STARTUP = "PRE_STARTUP", a.STARTUP = "STARTUP", a.POST_STARTUP = "POST_STARTUP", a.FIXED_UPDATE = "FIXED_UPDATE", a.PRE_UPDATE = "PRE_UPDATE", a.UPDATE = "UPDATE", a.POST_UPDATE = "POST_UPDATE", a))(It || {});
|
|
1122
|
+
const L = [
|
|
1005
1123
|
"PRE_STARTUP",
|
|
1006
1124
|
"STARTUP",
|
|
1007
1125
|
"POST_STARTUP"
|
|
1008
1126
|
/* POST_STARTUP */
|
|
1009
|
-
],
|
|
1127
|
+
], C = [
|
|
1010
1128
|
"PRE_UPDATE",
|
|
1011
1129
|
"UPDATE",
|
|
1012
1130
|
"POST_UPDATE"
|
|
1013
1131
|
/* POST_UPDATE */
|
|
1014
1132
|
];
|
|
1015
|
-
class
|
|
1133
|
+
class St {
|
|
1016
1134
|
label_systems = /* @__PURE__ */ new Map();
|
|
1017
1135
|
sorted_cache = /* @__PURE__ */ new Map();
|
|
1018
1136
|
system_index = /* @__PURE__ */ new Map();
|
|
1137
|
+
system_last_run = /* @__PURE__ */ new Map();
|
|
1019
1138
|
next_insertion_order = 0;
|
|
1020
1139
|
constructor() {
|
|
1021
|
-
for (let t = 0; t <
|
|
1022
|
-
this.label_systems.set(
|
|
1140
|
+
for (let t = 0; t < L.length; t++)
|
|
1141
|
+
this.label_systems.set(L[t], []);
|
|
1023
1142
|
this.label_systems.set("FIXED_UPDATE", []);
|
|
1024
|
-
for (let t = 0; t <
|
|
1025
|
-
this.label_systems.set(
|
|
1143
|
+
for (let t = 0; t < C.length; t++)
|
|
1144
|
+
this.label_systems.set(C[t], []);
|
|
1026
1145
|
}
|
|
1027
1146
|
add_systems(t, ...e) {
|
|
1028
1147
|
for (const s of e) {
|
|
1029
|
-
const n = "system" in s ? s.system : s,
|
|
1148
|
+
const n = "system" in s ? s.system : s, i = "system" in s ? s.ordering : void 0, r = {
|
|
1030
1149
|
descriptor: n,
|
|
1031
1150
|
insertion_order: this.next_insertion_order++,
|
|
1032
|
-
before: new Set(
|
|
1033
|
-
after: new Set(
|
|
1151
|
+
before: new Set(i?.before ?? []),
|
|
1152
|
+
after: new Set(i?.after ?? [])
|
|
1034
1153
|
};
|
|
1035
|
-
this.label_systems.get(t).push(
|
|
1154
|
+
this.label_systems.get(t).push(r), this.system_index.set(n, t), this.system_last_run.set(n, 0), this.sorted_cache.delete(t);
|
|
1036
1155
|
}
|
|
1037
1156
|
}
|
|
1038
1157
|
remove_system(t) {
|
|
1039
1158
|
const e = this.system_index.get(t);
|
|
1040
1159
|
if (e === void 0) return;
|
|
1041
|
-
const s = this.label_systems.get(e), n = s.findIndex((
|
|
1160
|
+
const s = this.label_systems.get(e), n = s.findIndex((i) => i.descriptor === t);
|
|
1042
1161
|
if (n !== -1) {
|
|
1043
|
-
const
|
|
1044
|
-
n !==
|
|
1045
|
-
for (const
|
|
1046
|
-
|
|
1162
|
+
const i = s.length - 1;
|
|
1163
|
+
n !== i && (s[n] = s[i]), s.pop();
|
|
1164
|
+
for (const r of s)
|
|
1165
|
+
r.before.delete(t), r.after.delete(t);
|
|
1047
1166
|
}
|
|
1048
|
-
this.system_index.delete(t), this.sorted_cache.delete(e);
|
|
1167
|
+
this.system_index.delete(t), this.system_last_run.delete(t), this.sorted_cache.delete(e);
|
|
1049
1168
|
}
|
|
1050
|
-
run_startup(t) {
|
|
1051
|
-
for (const
|
|
1052
|
-
this.run_label(
|
|
1169
|
+
run_startup(t, e) {
|
|
1170
|
+
for (const s of L)
|
|
1171
|
+
this.run_label(s, t, pt, e);
|
|
1053
1172
|
}
|
|
1054
|
-
run_update(t, e) {
|
|
1055
|
-
for (const
|
|
1056
|
-
this.run_label(
|
|
1173
|
+
run_update(t, e, s) {
|
|
1174
|
+
for (const n of C)
|
|
1175
|
+
this.run_label(n, t, e, s);
|
|
1057
1176
|
}
|
|
1058
|
-
run_fixed_update(t, e) {
|
|
1059
|
-
this.run_label("FIXED_UPDATE", t, e);
|
|
1177
|
+
run_fixed_update(t, e, s) {
|
|
1178
|
+
this.run_label("FIXED_UPDATE", t, e, s);
|
|
1060
1179
|
}
|
|
1061
1180
|
has_fixed_systems() {
|
|
1062
1181
|
return this.label_systems.get(
|
|
@@ -1077,93 +1196,96 @@ class kt {
|
|
|
1077
1196
|
clear() {
|
|
1078
1197
|
for (const t of this.label_systems.values())
|
|
1079
1198
|
t.length = 0;
|
|
1080
|
-
this.sorted_cache.clear(), this.system_index.clear();
|
|
1199
|
+
this.sorted_cache.clear(), this.system_index.clear(), this.system_last_run.clear();
|
|
1081
1200
|
}
|
|
1082
|
-
run_label(t, e, s) {
|
|
1083
|
-
const
|
|
1084
|
-
for (let r = 0; r <
|
|
1085
|
-
n[r].fn(e, s);
|
|
1201
|
+
run_label(t, e, s, n) {
|
|
1202
|
+
const i = this.get_sorted(t);
|
|
1203
|
+
for (let r = 0; r < i.length; r++)
|
|
1204
|
+
this.system_last_run.set(i[r], n), e.last_run_tick = n, i[r].fn(e, s);
|
|
1086
1205
|
e.flush();
|
|
1087
1206
|
}
|
|
1088
1207
|
get_sorted(t) {
|
|
1089
1208
|
const e = this.sorted_cache.get(t);
|
|
1090
1209
|
if (e !== void 0) return e;
|
|
1091
|
-
const s = this.label_systems.get(t), n = this.
|
|
1210
|
+
const s = this.label_systems.get(t), n = this.sort_systems(s, t);
|
|
1092
1211
|
return this.sorted_cache.set(t, n), n;
|
|
1093
1212
|
}
|
|
1094
1213
|
/**
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1214
|
+
* Delegates to the shared topological_sort utility.
|
|
1215
|
+
* Builds the dependency edge map from before/after constraints, then
|
|
1216
|
+
* catches any cycle TypeError and re-throws as ECSError.
|
|
1097
1217
|
*/
|
|
1098
|
-
|
|
1218
|
+
sort_systems(t, e) {
|
|
1099
1219
|
if (t.length === 0) return [];
|
|
1100
|
-
const s =
|
|
1101
|
-
for (const
|
|
1102
|
-
s.
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
n.get(o.descriptor) === 0 && _.push(o.descriptor);
|
|
1112
|
-
_.sort((o, h) => r.get(h) - r.get(o));
|
|
1113
|
-
const c = [];
|
|
1114
|
-
for (; _.length > 0; ) {
|
|
1115
|
-
const o = _.pop();
|
|
1116
|
-
c.push(o);
|
|
1117
|
-
for (const h of s.get(o)) {
|
|
1118
|
-
const a = n.get(h) - 1;
|
|
1119
|
-
n.set(h, a), a === 0 && _.push(h);
|
|
1120
|
-
}
|
|
1121
|
-
_.sort((h, a) => r.get(a) - r.get(h));
|
|
1220
|
+
const s = [], n = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set();
|
|
1221
|
+
for (const _ of t)
|
|
1222
|
+
s.push(_.descriptor), n.set(_.descriptor, _.insertion_order), i.add(_.descriptor);
|
|
1223
|
+
const r = /* @__PURE__ */ new Map();
|
|
1224
|
+
for (const _ of t)
|
|
1225
|
+
r.set(_.descriptor, []);
|
|
1226
|
+
for (const _ of t) {
|
|
1227
|
+
for (const h of _.before)
|
|
1228
|
+
i.has(h) && r.get(_.descriptor).push(h);
|
|
1229
|
+
for (const h of _.after)
|
|
1230
|
+
i.has(h) && r.get(h).push(_.descriptor);
|
|
1122
1231
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1232
|
+
const c = (_, h) => n.get(_) - n.get(h), o = (_) => _.name ?? `system_${_.id}`;
|
|
1233
|
+
try {
|
|
1234
|
+
return dt(s, r, c, o);
|
|
1235
|
+
} catch (_) {
|
|
1236
|
+
throw _ instanceof TypeError ? new O(
|
|
1237
|
+
D.CIRCULAR_SYSTEM_DEPENDENCY,
|
|
1238
|
+
`Circular system dependency detected in ${e}: ${_.message}`
|
|
1239
|
+
) : _;
|
|
1129
1240
|
}
|
|
1130
|
-
return c;
|
|
1131
1241
|
}
|
|
1132
1242
|
}
|
|
1133
1243
|
const W = /* @__PURE__ */ new WeakMap();
|
|
1134
|
-
function
|
|
1135
|
-
let e = W.get(
|
|
1244
|
+
function B(a, t) {
|
|
1245
|
+
let e = W.get(a);
|
|
1136
1246
|
if (!e) {
|
|
1137
1247
|
e = /* @__PURE__ */ Object.create(null);
|
|
1138
|
-
const { field_names:
|
|
1139
|
-
for (let
|
|
1140
|
-
const
|
|
1141
|
-
Object.defineProperty(e, r
|
|
1248
|
+
const { field_names: i } = a.layout;
|
|
1249
|
+
for (let r = 0; r < i.length; r++) {
|
|
1250
|
+
const c = r;
|
|
1251
|
+
Object.defineProperty(e, i[r], {
|
|
1142
1252
|
get() {
|
|
1143
|
-
return this._columns[
|
|
1253
|
+
return this._columns[c][this._row];
|
|
1144
1254
|
},
|
|
1145
|
-
set(
|
|
1146
|
-
this._columns[
|
|
1255
|
+
set(o) {
|
|
1256
|
+
this._columns[c][this._row] = o;
|
|
1147
1257
|
},
|
|
1148
1258
|
enumerable: !0,
|
|
1149
1259
|
configurable: !1
|
|
1150
1260
|
});
|
|
1151
1261
|
}
|
|
1152
|
-
W.set(
|
|
1262
|
+
W.set(a, e);
|
|
1153
1263
|
}
|
|
1154
|
-
const s = Object.create(e), n = new Array(
|
|
1155
|
-
for (let
|
|
1264
|
+
const s = Object.create(e), n = new Array(a.columns.length);
|
|
1265
|
+
for (let i = 0; i < a.columns.length; i++) n[i] = a.columns[i].buf;
|
|
1156
1266
|
return s._columns = n, s._row = t, s;
|
|
1157
1267
|
}
|
|
1158
|
-
class
|
|
1268
|
+
class Dt {
|
|
1159
1269
|
_archetypes;
|
|
1160
1270
|
_defs;
|
|
1161
1271
|
_resolver;
|
|
1162
1272
|
_include;
|
|
1163
1273
|
_exclude;
|
|
1164
1274
|
_any_of;
|
|
1165
|
-
|
|
1166
|
-
|
|
1275
|
+
_non_empty_archetypes = [];
|
|
1276
|
+
_non_empty_dirty = !0;
|
|
1277
|
+
// Per-Query composition caches — single-component fast path.
|
|
1278
|
+
// The final Query produced by _resolve_query is already cached by the
|
|
1279
|
+
// resolver, but the caller pays a BitSet copy + defs slice per call
|
|
1280
|
+
// before the resolver can hash and hit that cache. These caches
|
|
1281
|
+
// short-circuit that allocation path for the common single-component
|
|
1282
|
+
// composition shape (q.and(X), q.changed(X), etc).
|
|
1283
|
+
_and_cache_single = null;
|
|
1284
|
+
_not_cache_single = null;
|
|
1285
|
+
_any_of_cache_single = null;
|
|
1286
|
+
_changed_cache_single = null;
|
|
1287
|
+
constructor(t, e, s, n, i, r) {
|
|
1288
|
+
this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = i, this._any_of = r;
|
|
1167
1289
|
}
|
|
1168
1290
|
/** Number of matching archetypes (including empty ones). */
|
|
1169
1291
|
get archetype_count() {
|
|
@@ -1179,27 +1301,43 @@ class Pt {
|
|
|
1179
1301
|
get archetypes() {
|
|
1180
1302
|
return this._archetypes;
|
|
1181
1303
|
}
|
|
1182
|
-
/** Iterate non-empty archetypes. Skips archetypes with zero entities. */
|
|
1183
|
-
*[Symbol.iterator]() {
|
|
1184
|
-
const t = this._archetypes;
|
|
1185
|
-
for (let e = 0; e < t.length; e++)
|
|
1186
|
-
t[e].entity_count > 0 && (yield t[e]);
|
|
1187
|
-
}
|
|
1188
1304
|
/** Extend required component set. Returns a new (cached) Query. */
|
|
1189
1305
|
and(...t) {
|
|
1306
|
+
if (t.length === 1) {
|
|
1307
|
+
const n = t[0], i = this._and_cache_single;
|
|
1308
|
+
if (i !== null) {
|
|
1309
|
+
const _ = i.get(n);
|
|
1310
|
+
if (_ !== void 0) return _;
|
|
1311
|
+
}
|
|
1312
|
+
const r = this._include.copy(), c = this._defs.slice();
|
|
1313
|
+
r.has(n) || (r.set(n), c.push(t[0]));
|
|
1314
|
+
const o = this._resolver._resolve_query(r, this._exclude, this._any_of, c);
|
|
1315
|
+
return (this._and_cache_single ??= /* @__PURE__ */ new Map()).set(n, o), o;
|
|
1316
|
+
}
|
|
1190
1317
|
const e = this._include.copy(), s = this._defs.slice();
|
|
1191
1318
|
for (let n = 0; n < t.length; n++)
|
|
1192
1319
|
e.has(t[n]) || (e.set(t[n]), s.push(t[n]));
|
|
1193
|
-
return this._resolver._resolve_query(
|
|
1194
|
-
e,
|
|
1195
|
-
this._exclude,
|
|
1196
|
-
this._any_of,
|
|
1197
|
-
s
|
|
1198
|
-
);
|
|
1320
|
+
return this._resolver._resolve_query(e, this._exclude, this._any_of, s);
|
|
1199
1321
|
}
|
|
1200
1322
|
/** Exclude archetypes that have any of these components. */
|
|
1201
1323
|
not(...t) {
|
|
1202
|
-
|
|
1324
|
+
if (t.length === 1) {
|
|
1325
|
+
const s = t[0], n = this._not_cache_single;
|
|
1326
|
+
if (n !== null) {
|
|
1327
|
+
const c = n.get(s);
|
|
1328
|
+
if (c !== void 0) return c;
|
|
1329
|
+
}
|
|
1330
|
+
const i = this._exclude ? this._exclude.copy() : new p();
|
|
1331
|
+
i.set(s);
|
|
1332
|
+
const r = this._resolver._resolve_query(
|
|
1333
|
+
this._include,
|
|
1334
|
+
i,
|
|
1335
|
+
this._any_of,
|
|
1336
|
+
this._defs
|
|
1337
|
+
);
|
|
1338
|
+
return (this._not_cache_single ??= /* @__PURE__ */ new Map()).set(s, r), r;
|
|
1339
|
+
}
|
|
1340
|
+
const e = this._exclude ? this._exclude.copy() : new p();
|
|
1203
1341
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
1204
1342
|
return this._resolver._resolve_query(
|
|
1205
1343
|
this._include,
|
|
@@ -1208,9 +1346,45 @@ class Pt {
|
|
|
1208
1346
|
this._defs
|
|
1209
1347
|
);
|
|
1210
1348
|
}
|
|
1349
|
+
for_each(t) {
|
|
1350
|
+
const e = this._non_empty();
|
|
1351
|
+
for (let s = 0; s < e.length; s++)
|
|
1352
|
+
t(e[s]);
|
|
1353
|
+
}
|
|
1354
|
+
/** @internal — called by Store after flush and archetype push. */
|
|
1355
|
+
mark_non_empty_dirty() {
|
|
1356
|
+
this._non_empty_dirty = !0;
|
|
1357
|
+
}
|
|
1358
|
+
/** @internal — used by ChangedQuery. Rebuild non-empty archetype list if dirty, return cached result. */
|
|
1359
|
+
_non_empty() {
|
|
1360
|
+
if (this._non_empty_dirty) {
|
|
1361
|
+
const t = this._archetypes, e = this._non_empty_archetypes;
|
|
1362
|
+
e.length = 0;
|
|
1363
|
+
for (let s = 0; s < t.length; s++)
|
|
1364
|
+
t[s].entity_count > 0 && e.push(t[s]);
|
|
1365
|
+
this._non_empty_dirty = !1;
|
|
1366
|
+
}
|
|
1367
|
+
return this._non_empty_archetypes;
|
|
1368
|
+
}
|
|
1211
1369
|
/** Require at least one of these components. */
|
|
1212
1370
|
any_of(...t) {
|
|
1213
|
-
|
|
1371
|
+
if (t.length === 1) {
|
|
1372
|
+
const s = t[0], n = this._any_of_cache_single;
|
|
1373
|
+
if (n !== null) {
|
|
1374
|
+
const c = n.get(s);
|
|
1375
|
+
if (c !== void 0) return c;
|
|
1376
|
+
}
|
|
1377
|
+
const i = this._any_of ? this._any_of.copy() : new p();
|
|
1378
|
+
i.set(s);
|
|
1379
|
+
const r = this._resolver._resolve_query(
|
|
1380
|
+
this._include,
|
|
1381
|
+
this._exclude,
|
|
1382
|
+
i,
|
|
1383
|
+
this._defs
|
|
1384
|
+
);
|
|
1385
|
+
return (this._any_of_cache_single ??= /* @__PURE__ */ new Map()).set(s, r), r;
|
|
1386
|
+
}
|
|
1387
|
+
const e = this._any_of ? this._any_of.copy() : new p();
|
|
1214
1388
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
1215
1389
|
return this._resolver._resolve_query(
|
|
1216
1390
|
this._include,
|
|
@@ -1219,19 +1393,43 @@ class Pt {
|
|
|
1219
1393
|
this._defs
|
|
1220
1394
|
);
|
|
1221
1395
|
}
|
|
1396
|
+
/** Create a ChangedQuery that filters archetypes by change tick. */
|
|
1397
|
+
changed(...t) {
|
|
1398
|
+
if (t.length === 1) {
|
|
1399
|
+
const s = t[0], n = this._changed_cache_single;
|
|
1400
|
+
if (n !== null) {
|
|
1401
|
+
const r = n.get(s);
|
|
1402
|
+
if (r !== void 0) return r;
|
|
1403
|
+
}
|
|
1404
|
+
const i = new $(this, [s]);
|
|
1405
|
+
return (this._changed_cache_single ??= /* @__PURE__ */ new Map()).set(s, i), i;
|
|
1406
|
+
}
|
|
1407
|
+
const e = new Array(t.length);
|
|
1408
|
+
for (let s = 0; s < t.length; s++) e[s] = t[s];
|
|
1409
|
+
return new $(this, e);
|
|
1410
|
+
}
|
|
1411
|
+
/** @internal — reads last_run_tick from the resolver (ECS). */
|
|
1412
|
+
_ctx_last_run_tick() {
|
|
1413
|
+
return this._resolver._get_last_run_tick();
|
|
1414
|
+
}
|
|
1222
1415
|
}
|
|
1223
|
-
class
|
|
1416
|
+
class Rt {
|
|
1224
1417
|
constructor(t) {
|
|
1225
1418
|
this._resolver = t;
|
|
1226
1419
|
}
|
|
1227
1420
|
every(...t) {
|
|
1228
|
-
const e = new
|
|
1421
|
+
const e = new p();
|
|
1229
1422
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
1230
1423
|
return this._resolver._resolve_query(e, null, null, t);
|
|
1231
1424
|
}
|
|
1232
1425
|
}
|
|
1233
|
-
class
|
|
1426
|
+
class Nt {
|
|
1234
1427
|
store;
|
|
1428
|
+
last_run_tick = 0;
|
|
1429
|
+
/** Current world tick. Use this for write ticks in get_column_mut. */
|
|
1430
|
+
get world_tick() {
|
|
1431
|
+
return this.store._tick;
|
|
1432
|
+
}
|
|
1235
1433
|
constructor(t) {
|
|
1236
1434
|
this.store = t;
|
|
1237
1435
|
}
|
|
@@ -1239,24 +1437,29 @@ class Ot {
|
|
|
1239
1437
|
return this.store.create_entity();
|
|
1240
1438
|
}
|
|
1241
1439
|
get_field(t, e, s) {
|
|
1242
|
-
const n = this.store.get_entity_archetype(t),
|
|
1243
|
-
return n.read_field(
|
|
1440
|
+
const n = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t);
|
|
1441
|
+
return n.read_field(i, e, s);
|
|
1244
1442
|
}
|
|
1245
1443
|
set_field(t, e, s, n) {
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1444
|
+
const i = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t), c = i.get_column_mut(e, s, this.store._tick);
|
|
1445
|
+
c[r] = n;
|
|
1248
1446
|
}
|
|
1249
|
-
/** Create a cached component reference for a single entity. See ref.ts. */
|
|
1447
|
+
/** Create a cached read-only component reference for a single entity. See ref.ts. */
|
|
1250
1448
|
ref(t, e) {
|
|
1251
1449
|
const s = this.store.get_entity_archetype(e), n = this.store.get_entity_row(e);
|
|
1252
|
-
return
|
|
1450
|
+
return B(s.column_groups[t], n);
|
|
1451
|
+
}
|
|
1452
|
+
/** Create a cached mutable component reference. Marks the component as changed. */
|
|
1453
|
+
ref_mut(t, e) {
|
|
1454
|
+
const s = this.store.get_entity_archetype(e), n = this.store.get_entity_row(e);
|
|
1455
|
+
return s._changed_tick[t] = this.store._tick, B(s.column_groups[t], n);
|
|
1253
1456
|
}
|
|
1254
1457
|
/** Buffer an entity for deferred destruction (applied at phase flush). */
|
|
1255
1458
|
destroy_entity(t) {
|
|
1256
1459
|
return this.store.destroy_entity_deferred(t), this;
|
|
1257
1460
|
}
|
|
1258
1461
|
add_component(t, e, s) {
|
|
1259
|
-
return this.store.add_component_deferred(t, e, s ??
|
|
1462
|
+
return this.store.add_component_deferred(t, e, s ?? q), this;
|
|
1260
1463
|
}
|
|
1261
1464
|
remove_component(t, e) {
|
|
1262
1465
|
return this.store.remove_component_deferred(t, e), this;
|
|
@@ -1266,30 +1469,55 @@ class Ot {
|
|
|
1266
1469
|
this.store.flush_structural(), this.store.flush_destroyed();
|
|
1267
1470
|
}
|
|
1268
1471
|
emit(t, e) {
|
|
1269
|
-
|
|
1472
|
+
const s = this.store.get_event_def_by_key(t);
|
|
1473
|
+
e === void 0 ? this.store.emit_signal(s) : this.store.emit_event(s, e);
|
|
1270
1474
|
}
|
|
1271
1475
|
read(t) {
|
|
1272
|
-
|
|
1476
|
+
const e = this.store.get_event_def_by_key(t);
|
|
1477
|
+
return this.store.get_event_reader(e);
|
|
1273
1478
|
}
|
|
1274
1479
|
// =======================================================
|
|
1275
1480
|
// Resources
|
|
1276
1481
|
// =======================================================
|
|
1277
1482
|
resource(t) {
|
|
1278
|
-
return this.store.
|
|
1483
|
+
return this.store.get_resource(t);
|
|
1279
1484
|
}
|
|
1280
1485
|
set_resource(t, e) {
|
|
1281
|
-
this.store.
|
|
1486
|
+
this.store.set_resource(t, e);
|
|
1487
|
+
}
|
|
1488
|
+
has_resource(t) {
|
|
1489
|
+
return this.store.has_resource(t);
|
|
1282
1490
|
}
|
|
1283
1491
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1492
|
+
class $ {
|
|
1493
|
+
_query;
|
|
1494
|
+
_changed_ids;
|
|
1495
|
+
constructor(t, e) {
|
|
1496
|
+
this._query = t, this._changed_ids = e;
|
|
1497
|
+
}
|
|
1498
|
+
for_each(t) {
|
|
1499
|
+
const e = this._query._ctx_last_run_tick(), s = this._query._non_empty(), n = this._changed_ids;
|
|
1500
|
+
for (let i = 0; i < s.length; i++) {
|
|
1501
|
+
const r = s[i];
|
|
1502
|
+
for (let c = 0; c < n.length; c++)
|
|
1503
|
+
if (r._changed_tick[n[c]] >= e) {
|
|
1504
|
+
t(r);
|
|
1505
|
+
break;
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
const Pt = (a) => F(
|
|
1511
|
+
a
|
|
1286
1512
|
);
|
|
1287
|
-
class
|
|
1513
|
+
class Ut {
|
|
1288
1514
|
store;
|
|
1289
1515
|
schedule;
|
|
1290
1516
|
ctx;
|
|
1291
1517
|
systems = /* @__PURE__ */ new Set();
|
|
1292
1518
|
next_system_id = 0;
|
|
1519
|
+
// Tick counter for change detection
|
|
1520
|
+
_tick = 0;
|
|
1293
1521
|
// Fixed timestep accumulator
|
|
1294
1522
|
_fixed_timestep;
|
|
1295
1523
|
_accumulator = 0;
|
|
@@ -1298,9 +1526,9 @@ class Nt {
|
|
|
1298
1526
|
// Multiple queries can share the same hash (collision), so each bucket is an array.
|
|
1299
1527
|
query_cache = /* @__PURE__ */ new Map();
|
|
1300
1528
|
// Reusable BitSet for building query masks — avoids allocation per query() call
|
|
1301
|
-
scratch_mask = new
|
|
1529
|
+
scratch_mask = new p();
|
|
1302
1530
|
constructor(t) {
|
|
1303
|
-
this.store = new
|
|
1531
|
+
this.store = new xt(t?.initial_capacity), this.schedule = new St(), this.ctx = new Nt(this.store), this._fixed_timestep = t?.fixed_timestep ?? yt, this._max_fixed_steps = t?.max_fixed_steps ?? mt;
|
|
1304
1532
|
}
|
|
1305
1533
|
get fixed_timestep() {
|
|
1306
1534
|
return this._fixed_timestep;
|
|
@@ -1315,7 +1543,7 @@ class Nt {
|
|
|
1315
1543
|
register_component(t, e) {
|
|
1316
1544
|
if (Array.isArray(t)) {
|
|
1317
1545
|
const s = e ?? "f64", n = /* @__PURE__ */ Object.create(null);
|
|
1318
|
-
for (const
|
|
1546
|
+
for (const i of t) n[i] = s;
|
|
1319
1547
|
return this.store.register_component(n);
|
|
1320
1548
|
}
|
|
1321
1549
|
return this.store.register_component(t);
|
|
@@ -1323,23 +1551,23 @@ class Nt {
|
|
|
1323
1551
|
register_tag() {
|
|
1324
1552
|
return this.store.register_component({});
|
|
1325
1553
|
}
|
|
1326
|
-
register_event(t) {
|
|
1327
|
-
|
|
1554
|
+
register_event(t, e) {
|
|
1555
|
+
this.store.register_event_by_key(t, e);
|
|
1328
1556
|
}
|
|
1329
|
-
register_signal() {
|
|
1330
|
-
|
|
1557
|
+
register_signal(t) {
|
|
1558
|
+
this.store.register_event_by_key(t, []);
|
|
1331
1559
|
}
|
|
1332
1560
|
register_resource(t, e) {
|
|
1333
|
-
|
|
1334
|
-
t,
|
|
1335
|
-
e
|
|
1336
|
-
);
|
|
1561
|
+
this.store.register_resource(t, e);
|
|
1337
1562
|
}
|
|
1338
1563
|
resource(t) {
|
|
1339
|
-
return this.store.
|
|
1564
|
+
return this.store.get_resource(t);
|
|
1340
1565
|
}
|
|
1341
1566
|
set_resource(t, e) {
|
|
1342
|
-
this.store.
|
|
1567
|
+
this.store.set_resource(t, e);
|
|
1568
|
+
}
|
|
1569
|
+
has_resource(t) {
|
|
1570
|
+
return this.store.has_resource(t);
|
|
1343
1571
|
}
|
|
1344
1572
|
create_entity() {
|
|
1345
1573
|
return this.store.create_entity();
|
|
@@ -1354,7 +1582,7 @@ class Nt {
|
|
|
1354
1582
|
return this.store.entity_count;
|
|
1355
1583
|
}
|
|
1356
1584
|
add_component(t, e, s) {
|
|
1357
|
-
return this.store.add_component(t, e, s ??
|
|
1585
|
+
return this.store.add_component(t, e, s ?? q), this;
|
|
1358
1586
|
}
|
|
1359
1587
|
add_components(t, e) {
|
|
1360
1588
|
this.store.add_components(t, e);
|
|
@@ -1379,15 +1607,20 @@ class Nt {
|
|
|
1379
1607
|
this.store.batch_remove_component(t, e);
|
|
1380
1608
|
}
|
|
1381
1609
|
get_field(t, e, s) {
|
|
1382
|
-
const n = this.store.get_entity_archetype(t),
|
|
1383
|
-
return n.read_field(
|
|
1610
|
+
const n = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t);
|
|
1611
|
+
return n.read_field(i, e, s);
|
|
1384
1612
|
}
|
|
1385
1613
|
set_field(t, e, s, n) {
|
|
1386
|
-
const
|
|
1387
|
-
|
|
1614
|
+
const i = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t), c = i.get_column_mut(e, s, this.store._tick);
|
|
1615
|
+
c[r] = n;
|
|
1388
1616
|
}
|
|
1389
1617
|
emit(t, e) {
|
|
1390
|
-
|
|
1618
|
+
const s = this.store.get_event_def_by_key(t);
|
|
1619
|
+
e === void 0 ? this.store.emit_signal(s) : this.store.emit_event(s, e);
|
|
1620
|
+
}
|
|
1621
|
+
read(t) {
|
|
1622
|
+
const e = this.store.get_event_def_by_key(t);
|
|
1623
|
+
return this.store.get_event_reader(e);
|
|
1391
1624
|
}
|
|
1392
1625
|
query(...t) {
|
|
1393
1626
|
const e = this.scratch_mask;
|
|
@@ -1396,15 +1629,14 @@ class Nt {
|
|
|
1396
1629
|
e.set(t[s]);
|
|
1397
1630
|
return this._resolve_query(e.copy(), null, null, t);
|
|
1398
1631
|
}
|
|
1632
|
+
_get_last_run_tick() {
|
|
1633
|
+
return this.ctx.last_run_tick;
|
|
1634
|
+
}
|
|
1399
1635
|
/** QueryResolver implementation — creates or retrieves a cached Query. */
|
|
1400
1636
|
_resolve_query(t, e, s, n) {
|
|
1401
|
-
const
|
|
1402
|
-
if (
|
|
1403
|
-
const h = this.store.register_query(
|
|
1404
|
-
t,
|
|
1405
|
-
e ?? void 0,
|
|
1406
|
-
s ?? void 0
|
|
1407
|
-
), a = new Pt(
|
|
1637
|
+
const i = t.hash(), r = e ? e.hash() : 0, c = s ? s.hash() : 0, o = i ^ Math.imul(r, ut) ^ Math.imul(c, ft) | 0, _ = this._find_cached(o, t, e, s);
|
|
1638
|
+
if (_ !== void 0) return _.query;
|
|
1639
|
+
const h = this.store.register_query(t, e ?? void 0, s ?? void 0), l = new Dt(
|
|
1408
1640
|
h,
|
|
1409
1641
|
n,
|
|
1410
1642
|
this,
|
|
@@ -1412,20 +1644,20 @@ class Nt {
|
|
|
1412
1644
|
e?.copy() ?? null,
|
|
1413
1645
|
s?.copy() ?? null
|
|
1414
1646
|
);
|
|
1415
|
-
return
|
|
1647
|
+
return this.store.update_query_ref(h, l), Q(this.query_cache, o, {
|
|
1416
1648
|
include_mask: t.copy(),
|
|
1417
1649
|
exclude_mask: e?.copy() ?? null,
|
|
1418
1650
|
any_of_mask: s?.copy() ?? null,
|
|
1419
|
-
query:
|
|
1420
|
-
}),
|
|
1651
|
+
query: l
|
|
1652
|
+
}), l;
|
|
1421
1653
|
}
|
|
1422
1654
|
_find_cached(t, e, s, n) {
|
|
1423
|
-
const
|
|
1424
|
-
if (
|
|
1425
|
-
for (let
|
|
1426
|
-
const
|
|
1427
|
-
if (!(!
|
|
1428
|
-
return
|
|
1655
|
+
const i = this.query_cache.get(t);
|
|
1656
|
+
if (i)
|
|
1657
|
+
for (let r = 0; r < i.length; r++) {
|
|
1658
|
+
const c = i[r];
|
|
1659
|
+
if (!(!c.include_mask.equals(e) || !(s === null ? c.exclude_mask === null : c.exclude_mask !== null && c.exclude_mask.equals(s)) || !(n === null ? c.any_of_mask === null : c.any_of_mask !== null && c.any_of_mask.equals(n))))
|
|
1660
|
+
return c;
|
|
1429
1661
|
}
|
|
1430
1662
|
}
|
|
1431
1663
|
// any: overload implementation must unify bare fn, (fn, query_fn), and SystemConfig
|
|
@@ -1433,16 +1665,14 @@ class Nt {
|
|
|
1433
1665
|
let s;
|
|
1434
1666
|
if (typeof t == "function")
|
|
1435
1667
|
if (e !== void 0) {
|
|
1436
|
-
const
|
|
1437
|
-
s = { fn: (
|
|
1668
|
+
const r = e(new Rt(this)), c = this.ctx, o = t;
|
|
1669
|
+
s = { fn: (_, h) => o(r, c, h) };
|
|
1438
1670
|
} else
|
|
1439
1671
|
s = { fn: t };
|
|
1440
1672
|
else
|
|
1441
1673
|
s = t;
|
|
1442
|
-
const n =
|
|
1443
|
-
|
|
1444
|
-
);
|
|
1445
|
-
return this.systems.add(r), r;
|
|
1674
|
+
const n = Pt(this.next_system_id++), i = Object.freeze(Object.assign({ id: n }, s));
|
|
1675
|
+
return this.systems.add(i), i;
|
|
1446
1676
|
}
|
|
1447
1677
|
add_systems(t, ...e) {
|
|
1448
1678
|
return this.schedule.add_systems(t, ...e), this;
|
|
@@ -1456,16 +1686,16 @@ class Nt {
|
|
|
1456
1686
|
startup() {
|
|
1457
1687
|
for (const t of this.systems.values())
|
|
1458
1688
|
t.on_added?.(this.ctx);
|
|
1459
|
-
this.schedule.run_startup(this.ctx);
|
|
1689
|
+
this.schedule.run_startup(this.ctx, this._tick);
|
|
1460
1690
|
}
|
|
1461
1691
|
update(t) {
|
|
1462
|
-
if (this.schedule.has_fixed_systems()) {
|
|
1692
|
+
if (this.store._tick = this._tick, this.schedule.has_fixed_systems()) {
|
|
1463
1693
|
this._accumulator += t;
|
|
1464
1694
|
const e = this._max_fixed_steps * this._fixed_timestep;
|
|
1465
1695
|
for (this._accumulator > e && (this._accumulator = e); this._accumulator >= this._fixed_timestep; )
|
|
1466
|
-
this.schedule.run_fixed_update(this.ctx, this._fixed_timestep), this._accumulator -= this._fixed_timestep;
|
|
1696
|
+
this.schedule.run_fixed_update(this.ctx, this._fixed_timestep, this._tick), this._accumulator -= this._fixed_timestep;
|
|
1467
1697
|
}
|
|
1468
|
-
this.schedule.run_update(this.ctx, t), this.store.clear_events()
|
|
1698
|
+
this.schedule.run_update(this.ctx, t, this._tick), this.store.clear_events(), this._tick++;
|
|
1469
1699
|
}
|
|
1470
1700
|
flush() {
|
|
1471
1701
|
this.ctx.flush();
|
|
@@ -1476,10 +1706,17 @@ class Nt {
|
|
|
1476
1706
|
this.systems.clear(), this.schedule.clear();
|
|
1477
1707
|
}
|
|
1478
1708
|
}
|
|
1709
|
+
function Mt(a) {
|
|
1710
|
+
return Symbol(a);
|
|
1711
|
+
}
|
|
1479
1712
|
export {
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1713
|
+
$ as ChangedQuery,
|
|
1714
|
+
Ut as ECS,
|
|
1715
|
+
Dt as Query,
|
|
1716
|
+
Rt as QueryBuilder,
|
|
1717
|
+
It as SCHEDULE,
|
|
1718
|
+
Nt as SystemContext,
|
|
1719
|
+
Ot as event_key,
|
|
1720
|
+
Mt as resource_key,
|
|
1721
|
+
qt as signal_key
|
|
1485
1722
|
};
|