@oasys/oecs 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -164
- package/dist/archetype.d.ts +50 -13
- package/dist/archetype.d.ts.map +1 -1
- package/dist/component.d.ts +27 -10
- package/dist/component.d.ts.map +1 -1
- package/dist/ecs.d.ts +104 -0
- package/dist/ecs.d.ts.map +1 -0
- package/dist/entity.d.ts.map +1 -1
- package/dist/event.d.ts +2 -2
- package/dist/event.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +680 -400
- package/dist/query.d.ts +28 -31
- package/dist/query.d.ts.map +1 -1
- package/dist/ref.d.ts +19 -0
- package/dist/ref.d.ts.map +1 -0
- package/dist/resource.d.ts +23 -0
- package/dist/resource.d.ts.map +1 -0
- package/dist/schedule.d.ts +3 -3
- package/dist/schedule.d.ts.map +1 -1
- package/dist/store.d.ts +48 -29
- package/dist/store.d.ts.map +1 -1
- package/dist/system.d.ts +2 -2
- 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/bitset/bitset.d.ts +2 -2
- package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
- package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
- package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +9 -0
- package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
- package/dist/utils/constants.d.ts +20 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/error.d.ts +2 -9
- package/dist/utils/error.d.ts.map +1 -1
- package/package.json +2 -1
- package/dist/world.d.ts +0 -73
- package/dist/world.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,46 +1,34 @@
|
|
|
1
|
-
class
|
|
1
|
+
class H 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 z = /* @__PURE__ */ ((l) => (l.EID_MAX_INDEX_OVERFLOW = "EID_MAX_INDEX_OVERFLOW", l.EID_MAX_GEN_OVERFLOW = "EID_MAX_GEN_OVERFLOW", l.COMPONENT_NOT_REGISTERED = "COMPONENT_NOT_REGISTERED", l.ENTITY_NOT_ALIVE = "ENTITY_NOT_ALIVE", l.CIRCULAR_SYSTEM_DEPENDENCY = "CIRCULAR_SYSTEM_DEPENDENCY", l.DUPLICATE_SYSTEM = "DUPLICATE_SYSTEM", l.ARCHETYPE_NOT_FOUND = "ARCHETYPE_NOT_FOUND", l.RESOURCE_NOT_REGISTERED = "RESOURCE_NOT_REGISTERED", l))(z || {});
|
|
7
|
+
class Q extends H {
|
|
8
8
|
constructor(t, e, s) {
|
|
9
9
|
super(e ?? t, !0, s), this.category = t;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(t, e, s) {
|
|
15
|
-
super(e, !1, s), this.category = t;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
const P = (a) => Number.isInteger(a) && a >= 0;
|
|
19
|
-
function b(a, t, e) {
|
|
20
|
-
if (process.env.NODE_ENV !== "production" && !t(a))
|
|
21
|
-
throw new X(
|
|
22
|
-
Y.VALIDATION_FAIL_CONDITION,
|
|
23
|
-
`Expected value to meet validation: ${e}`
|
|
24
|
-
);
|
|
25
|
-
return a;
|
|
12
|
+
function N(l, t, e) {
|
|
13
|
+
return l;
|
|
26
14
|
}
|
|
27
|
-
const C = 4;
|
|
28
|
-
class
|
|
15
|
+
const v = -1, y = -1, D = Object.freeze(/* @__PURE__ */ Object.create(null)), k = 5, I = 31, J = 2166136261, Z = 16777619, tt = 2654435769, et = 1367130551, b = 16, C = 2, V = 1024, R = 0, j = 0, st = 31, nt = 1 / 60, rt = 4, it = 0, ot = 4;
|
|
16
|
+
class x {
|
|
29
17
|
_words;
|
|
30
18
|
constructor(t) {
|
|
31
|
-
this._words = t ?? new Array(
|
|
19
|
+
this._words = t ?? new Array(ot).fill(0);
|
|
32
20
|
}
|
|
33
21
|
has(t) {
|
|
34
|
-
const e = t >>>
|
|
35
|
-
return e >= this._words.length ? !1 : (this._words[e] & 1 << (t &
|
|
22
|
+
const e = t >>> k;
|
|
23
|
+
return e >= this._words.length ? !1 : (this._words[e] & 1 << (t & I)) !== 0;
|
|
36
24
|
}
|
|
37
25
|
set(t) {
|
|
38
|
-
const e = t >>>
|
|
39
|
-
e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t &
|
|
26
|
+
const e = t >>> k;
|
|
27
|
+
e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t & I);
|
|
40
28
|
}
|
|
41
29
|
clear(t) {
|
|
42
|
-
const e = t >>>
|
|
43
|
-
e >= this._words.length || (this._words[e] &= ~(1 << (t &
|
|
30
|
+
const e = t >>> k;
|
|
31
|
+
e >= this._words.length || (this._words[e] &= ~(1 << (t & I)));
|
|
44
32
|
}
|
|
45
33
|
/** True if any bit is set in both this and other (non-empty intersection). */
|
|
46
34
|
overlaps(t) {
|
|
@@ -68,25 +56,25 @@ class N {
|
|
|
68
56
|
return !0;
|
|
69
57
|
}
|
|
70
58
|
copy() {
|
|
71
|
-
return new
|
|
59
|
+
return new x(this._words.slice());
|
|
72
60
|
}
|
|
73
61
|
copy_with_set(t) {
|
|
74
|
-
const e = t >>>
|
|
62
|
+
const e = t >>> k, s = e + 1, n = this._words.length > s ? this._words.length : s, r = new Array(n).fill(0);
|
|
75
63
|
for (let i = 0; i < this._words.length; i++) r[i] = this._words[i];
|
|
76
|
-
return r[e] |= 1 << (t &
|
|
64
|
+
return r[e] |= 1 << (t & I), new x(r);
|
|
77
65
|
}
|
|
78
66
|
copy_with_clear(t) {
|
|
79
|
-
const e = this._words.slice(), s = t >>>
|
|
80
|
-
return s < e.length && (e[s] &= ~(1 << (t &
|
|
67
|
+
const e = this._words.slice(), s = t >>> k;
|
|
68
|
+
return s < e.length && (e[s] &= ~(1 << (t & I))), new x(e);
|
|
81
69
|
}
|
|
82
70
|
/** FNV-1a hash. Skips trailing zero words so differently-sized arrays with the same bits hash equally. */
|
|
83
71
|
hash() {
|
|
84
|
-
let t =
|
|
72
|
+
let t = J;
|
|
85
73
|
const e = this._words;
|
|
86
74
|
let s = e.length - 1;
|
|
87
75
|
for (; s >= 0 && e[s] === 0; ) s--;
|
|
88
76
|
for (let n = 0; n <= s; n++)
|
|
89
|
-
t ^= e[n], t = Math.imul(t,
|
|
77
|
+
t ^= e[n], t = Math.imul(t, Z);
|
|
90
78
|
return t;
|
|
91
79
|
}
|
|
92
80
|
/** Iterate all set bits via lowest-set-bit extraction. */
|
|
@@ -95,9 +83,9 @@ class N {
|
|
|
95
83
|
for (let s = 0; s < e.length; s++) {
|
|
96
84
|
let n = e[s];
|
|
97
85
|
if (n === 0) continue;
|
|
98
|
-
const r = s <<
|
|
86
|
+
const r = s << k;
|
|
99
87
|
for (; n !== 0; ) {
|
|
100
|
-
const i = n & -n >>> 0, _ =
|
|
88
|
+
const i = n & -n >>> 0, _ = I - Math.clz32(i);
|
|
101
89
|
t(r + _), n ^= i;
|
|
102
90
|
}
|
|
103
91
|
}
|
|
@@ -110,26 +98,144 @@ class N {
|
|
|
110
98
|
this._words = s;
|
|
111
99
|
}
|
|
112
100
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
101
|
+
class A {
|
|
102
|
+
constructor(t, e = b) {
|
|
103
|
+
this._ctor = t, this._buf = new t(e);
|
|
104
|
+
}
|
|
105
|
+
_buf;
|
|
106
|
+
_len = 0;
|
|
107
|
+
get length() {
|
|
108
|
+
return this._len;
|
|
109
|
+
}
|
|
110
|
+
push(t) {
|
|
111
|
+
this._len >= this._buf.length && this._grow(), this._buf[this._len++] = t;
|
|
112
|
+
}
|
|
113
|
+
pop() {
|
|
114
|
+
return this._buf[--this._len];
|
|
115
|
+
}
|
|
116
|
+
get(t) {
|
|
117
|
+
return this._buf[t];
|
|
118
|
+
}
|
|
119
|
+
set_at(t, e) {
|
|
120
|
+
this._buf[t] = e;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Move the last element into slot i, decrement length.
|
|
124
|
+
* Returns the value that was removed from slot i.
|
|
125
|
+
*/
|
|
126
|
+
swap_remove(t) {
|
|
127
|
+
const e = this._buf[t];
|
|
128
|
+
return this._buf[t] = this._buf[--this._len], e;
|
|
129
|
+
}
|
|
130
|
+
clear() {
|
|
131
|
+
this._len = 0;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Raw backing buffer. Valid data: indices 0..length-1.
|
|
135
|
+
* This reference is stable until the next push() that triggers a grow —
|
|
136
|
+
* do not cache across entity additions.
|
|
137
|
+
*/
|
|
138
|
+
get buf() {
|
|
139
|
+
return this._buf;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Zero-copy subarray view of valid data (0..length-1).
|
|
143
|
+
* Shares the backing buffer — invalidated if a subsequent push() grows.
|
|
144
|
+
*/
|
|
145
|
+
view() {
|
|
146
|
+
return this._buf.subarray(0, this._len);
|
|
147
|
+
}
|
|
148
|
+
[Symbol.iterator]() {
|
|
149
|
+
let t = 0;
|
|
150
|
+
const e = this._buf, s = this._len;
|
|
151
|
+
return {
|
|
152
|
+
next() {
|
|
153
|
+
return t < s ? { value: e[t++], done: !1 } : { value: 0, done: !0 };
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/** Ensure the backing buffer can hold at least `capacity` elements without growing. */
|
|
158
|
+
ensure_capacity(t) {
|
|
159
|
+
if (t <= this._buf.length) return;
|
|
160
|
+
let e = this._buf.length || 1;
|
|
161
|
+
for (; e < t; ) e *= C;
|
|
162
|
+
const s = new this._ctor(e);
|
|
163
|
+
s.set(this._buf.subarray(0, this._len)), this._buf = s;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Append `count` elements from `src` starting at `src_offset`.
|
|
167
|
+
* Grows if needed. Equivalent to push() in a loop but uses TypedArray.set().
|
|
168
|
+
*/
|
|
169
|
+
bulk_append(t, e, s) {
|
|
170
|
+
this.ensure_capacity(this._len + s), this._buf.set(t.subarray(e, e + s), this._len), this._len += s;
|
|
171
|
+
}
|
|
172
|
+
/** Append `count` zeroes. Grows if needed. */
|
|
173
|
+
bulk_append_zeroes(t) {
|
|
174
|
+
this.ensure_capacity(this._len + t), this._buf.fill(0, this._len, this._len + t), this._len += t;
|
|
175
|
+
}
|
|
176
|
+
_grow() {
|
|
177
|
+
const t = new this._ctor(this._buf.length * C);
|
|
178
|
+
t.set(this._buf), this._buf = t;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
class _t extends A {
|
|
182
|
+
constructor(t = b) {
|
|
183
|
+
super(Float32Array, t);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
class ct extends A {
|
|
187
|
+
constructor(t = b) {
|
|
188
|
+
super(Float64Array, t);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
class ht extends A {
|
|
192
|
+
constructor(t = b) {
|
|
193
|
+
super(Int8Array, t);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
class lt extends A {
|
|
197
|
+
constructor(t = b) {
|
|
198
|
+
super(Int16Array, t);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
class at extends A {
|
|
202
|
+
constructor(t = b) {
|
|
203
|
+
super(Int32Array, t);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
class dt extends A {
|
|
207
|
+
constructor(t = b) {
|
|
208
|
+
super(Uint8Array, t);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
class ut extends A {
|
|
212
|
+
constructor(t = b) {
|
|
213
|
+
super(Uint16Array, t);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
class B extends A {
|
|
217
|
+
constructor(t = b) {
|
|
218
|
+
super(Uint32Array, t);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const ft = {
|
|
222
|
+
f32: _t,
|
|
223
|
+
f64: ct,
|
|
224
|
+
i8: ht,
|
|
225
|
+
i16: lt,
|
|
226
|
+
i32: at,
|
|
227
|
+
u8: dt,
|
|
228
|
+
u16: ut,
|
|
229
|
+
u32: B
|
|
230
|
+
}, P = 20, F = (1 << P) - 1, gt = st - P, X = (1 << gt) - 1, mt = (l, t) => t << P | l, m = (l) => l & F, Y = (l) => l >> P, yt = (l) => N(
|
|
231
|
+
l
|
|
232
|
+
), pt = (l) => N(
|
|
233
|
+
l
|
|
129
234
|
);
|
|
130
|
-
class
|
|
235
|
+
class wt {
|
|
131
236
|
field_names;
|
|
132
237
|
columns;
|
|
238
|
+
// any: type-erased storage — channel is stored in Map<number, EventChannel>, F is lost
|
|
133
239
|
reader;
|
|
134
240
|
constructor(t) {
|
|
135
241
|
this.field_names = t, this.columns = [];
|
|
@@ -157,46 +263,92 @@ class B {
|
|
|
157
263
|
t[e].length = 0;
|
|
158
264
|
}
|
|
159
265
|
}
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
P,
|
|
163
|
-
"ArchetypeID must be a non-negative integer"
|
|
266
|
+
const vt = (l) => N(
|
|
267
|
+
l
|
|
164
268
|
);
|
|
165
|
-
class
|
|
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
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const bt = (l) => N(
|
|
304
|
+
l
|
|
305
|
+
);
|
|
306
|
+
class Tt {
|
|
166
307
|
id;
|
|
167
308
|
mask;
|
|
168
309
|
has_columns;
|
|
169
|
-
|
|
310
|
+
_entity_ids;
|
|
170
311
|
length = 0;
|
|
171
312
|
edges = [];
|
|
172
|
-
//
|
|
173
|
-
//
|
|
313
|
+
// --- Flat column storage ---
|
|
314
|
+
// Dense array of ALL columns across all components in this archetype.
|
|
315
|
+
_flat_columns = [];
|
|
316
|
+
// Sparse by ComponentID → starting index into _flat_columns.
|
|
317
|
+
_col_offset = [];
|
|
318
|
+
// Sparse by ComponentID → number of fields for that component.
|
|
319
|
+
_field_count = [];
|
|
320
|
+
// Sparse by ComponentID → field_index record (field name → offset within component).
|
|
321
|
+
_field_index = [];
|
|
322
|
+
// Sparse by ComponentID → field_names array.
|
|
323
|
+
_field_names = [];
|
|
324
|
+
// Sparse array indexed by ComponentID — kept for create_ref compatibility.
|
|
174
325
|
column_groups = [];
|
|
175
|
-
// Dense list of ComponentIDs that have columns — used
|
|
176
|
-
// data-bearing components in copy/add/remove operations.
|
|
326
|
+
// Dense list of ComponentIDs that have columns — used for copy_shared_from.
|
|
177
327
|
_column_ids = [];
|
|
178
|
-
constructor(t, e, s) {
|
|
179
|
-
if (this.id = t, this.mask = e, s)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
columns: i,
|
|
190
|
-
record: _
|
|
191
|
-
}, this._column_ids.push(r.component_id);
|
|
328
|
+
constructor(t, e, s, n = V) {
|
|
329
|
+
if (this.id = t, this.mask = e, this._entity_ids = new B(n), s) {
|
|
330
|
+
let r = 0;
|
|
331
|
+
for (let i = 0; i < s.length; i++) {
|
|
332
|
+
const _ = s[i], c = _.component_id, o = new Array(_.field_names.length);
|
|
333
|
+
this._col_offset[c] = r, this._field_count[c] = _.field_names.length, this._field_index[c] = _.field_index, this._field_names[c] = _.field_names;
|
|
334
|
+
for (let h = 0; h < _.field_names.length; h++) {
|
|
335
|
+
const a = new ft[_.field_types[h]](n);
|
|
336
|
+
o[h] = a, this._flat_columns[r++] = a;
|
|
337
|
+
}
|
|
338
|
+
this.column_groups[c] = { layout: _, columns: o }, this._column_ids.push(c);
|
|
192
339
|
}
|
|
340
|
+
}
|
|
193
341
|
this.has_columns = this._column_ids.length > 0;
|
|
194
342
|
}
|
|
195
343
|
get entity_count() {
|
|
196
344
|
return this.length;
|
|
197
345
|
}
|
|
346
|
+
/** Raw entity ID buffer. Valid data at indices 0..entity_count-1. */
|
|
347
|
+
get entity_ids() {
|
|
348
|
+
return this._entity_ids.buf;
|
|
349
|
+
}
|
|
198
350
|
get entity_list() {
|
|
199
|
-
return this.
|
|
351
|
+
return this._entity_ids.view();
|
|
200
352
|
}
|
|
201
353
|
has_component(t) {
|
|
202
354
|
return this.mask.has(t);
|
|
@@ -206,47 +358,39 @@ class K {
|
|
|
206
358
|
}
|
|
207
359
|
/** Get a single field's column. Valid data: indices 0..entity_count-1. */
|
|
208
360
|
get_column(t, e) {
|
|
209
|
-
const s = this.
|
|
210
|
-
|
|
211
|
-
throw new u(
|
|
212
|
-
d.COMPONENT_NOT_REGISTERED,
|
|
213
|
-
`Component ${t} not in archetype ${this.id}`
|
|
214
|
-
);
|
|
215
|
-
const n = s.layout.field_index[e];
|
|
216
|
-
if (process.env.NODE_ENV !== "production" && n === void 0)
|
|
217
|
-
throw new u(
|
|
218
|
-
d.COMPONENT_NOT_REGISTERED,
|
|
219
|
-
`Field "${e}" does not exist on component`
|
|
220
|
-
);
|
|
221
|
-
return s.columns[n];
|
|
222
|
-
}
|
|
223
|
-
/** Get all columns for a component as { fieldName: number[] }. */
|
|
224
|
-
get_column_group(t) {
|
|
225
|
-
const e = this.column_groups[t];
|
|
226
|
-
return e ? e.record : {};
|
|
361
|
+
const s = t, n = this._field_index[s][e];
|
|
362
|
+
return this._flat_columns[this._col_offset[s] + n].buf;
|
|
227
363
|
}
|
|
228
364
|
write_fields(t, e, s) {
|
|
229
|
-
const n = this.
|
|
230
|
-
if (
|
|
231
|
-
const
|
|
232
|
-
for (let
|
|
233
|
-
|
|
365
|
+
const n = e, r = this._col_offset[n];
|
|
366
|
+
if (r === void 0) return;
|
|
367
|
+
const i = this._field_names[n], _ = this._flat_columns;
|
|
368
|
+
for (let c = 0; c < i.length; c++)
|
|
369
|
+
_[r + c].buf[t] = s[i[c]];
|
|
370
|
+
}
|
|
371
|
+
/** Fast positional write: values[i] → field[i] in declaration order. No string lookup. */
|
|
372
|
+
write_fields_positional(t, e, s) {
|
|
373
|
+
const n = e, r = this._col_offset[n];
|
|
374
|
+
if (r === void 0) return;
|
|
375
|
+
const i = this._flat_columns;
|
|
376
|
+
for (let _ = 0; _ < s.length; _++)
|
|
377
|
+
i[r + _].buf[t] = s[_];
|
|
234
378
|
}
|
|
235
379
|
read_field(t, e, s) {
|
|
236
|
-
const n = this.
|
|
237
|
-
if (
|
|
238
|
-
const
|
|
239
|
-
return
|
|
380
|
+
const n = e, r = this._col_offset[n];
|
|
381
|
+
if (r === void 0) return NaN;
|
|
382
|
+
const i = this._field_index[n][s];
|
|
383
|
+
return i === void 0 ? NaN : this._flat_columns[r + i].buf[t];
|
|
240
384
|
}
|
|
241
385
|
/** Copy all shared component columns from source archetype at src_row into dst_row. */
|
|
242
386
|
copy_shared_from(t, e, s) {
|
|
243
|
-
const n = t.
|
|
244
|
-
for (let
|
|
245
|
-
const
|
|
246
|
-
if (
|
|
247
|
-
const
|
|
248
|
-
for (let
|
|
249
|
-
|
|
387
|
+
const n = t._col_offset, r = t._field_count, i = t._flat_columns, _ = this._flat_columns, c = this._column_ids;
|
|
388
|
+
for (let o = 0; o < c.length; o++) {
|
|
389
|
+
const h = c[o], a = n[h];
|
|
390
|
+
if (a === void 0) continue;
|
|
391
|
+
const u = this._col_offset[h], d = r[h];
|
|
392
|
+
for (let g = 0; g < d; g++)
|
|
393
|
+
_[u + g].buf[s] = i[a + g].buf[e];
|
|
250
394
|
}
|
|
251
395
|
}
|
|
252
396
|
/**
|
|
@@ -255,49 +399,88 @@ class K {
|
|
|
255
399
|
*/
|
|
256
400
|
add_entity(t) {
|
|
257
401
|
const e = this.length;
|
|
258
|
-
this.
|
|
259
|
-
const s = this.
|
|
260
|
-
for (let n = 0; n < s.length; n++)
|
|
261
|
-
|
|
262
|
-
for (let i = 0; i < r.columns.length; i++)
|
|
263
|
-
r.columns[i].push(0);
|
|
264
|
-
}
|
|
402
|
+
this._entity_ids.push(t);
|
|
403
|
+
const s = this._flat_columns;
|
|
404
|
+
for (let n = 0; n < s.length; n++)
|
|
405
|
+
s[n].push(0);
|
|
265
406
|
return this.length++, e;
|
|
266
407
|
}
|
|
267
408
|
/**
|
|
268
409
|
* Remove entity at row via swap-and-pop. Swaps the last entity into the
|
|
269
410
|
* vacated row to keep data dense. Returns the entity_index of the swapped
|
|
270
|
-
* entity (so Store can update its row), or
|
|
411
|
+
* entity (so Store can update its row), or NO_SWAP if no swap was needed.
|
|
271
412
|
*/
|
|
272
413
|
remove_entity(t) {
|
|
273
414
|
const e = this.length - 1;
|
|
274
|
-
let s =
|
|
275
|
-
const n = this.
|
|
415
|
+
let s = y;
|
|
416
|
+
const n = this._flat_columns, r = this._entity_ids.buf;
|
|
276
417
|
if (t !== e) {
|
|
277
|
-
|
|
278
|
-
for (let
|
|
279
|
-
|
|
280
|
-
for (let _ = 0; _ < i.columns.length; _++)
|
|
281
|
-
i.columns[_][t] = i.columns[_][e], i.columns[_].pop();
|
|
282
|
-
}
|
|
418
|
+
r[t] = r[e], s = m(r[t]);
|
|
419
|
+
for (let i = 0; i < n.length; i++)
|
|
420
|
+
n[i].swap_remove(t);
|
|
283
421
|
} else
|
|
284
|
-
for (let
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
i.columns[_].pop();
|
|
288
|
-
}
|
|
289
|
-
return this.entity_ids.pop(), this.length--, s;
|
|
422
|
+
for (let i = 0; i < n.length; i++)
|
|
423
|
+
n[i].pop();
|
|
424
|
+
return this._entity_ids.pop(), this.length--, s;
|
|
290
425
|
}
|
|
291
426
|
/** Tag-optimized add: skip column push entirely (no data to store). */
|
|
292
427
|
add_entity_tag(t) {
|
|
293
428
|
const e = this.length;
|
|
294
|
-
return this.
|
|
429
|
+
return this._entity_ids.push(t), this.length++, e;
|
|
295
430
|
}
|
|
296
431
|
/** Tag-optimized remove via swap-and-pop: skip column swap/pop entirely. */
|
|
297
432
|
remove_entity_tag(t) {
|
|
298
433
|
const e = this.length - 1;
|
|
299
|
-
let s =
|
|
300
|
-
|
|
434
|
+
let s = y;
|
|
435
|
+
const n = this._entity_ids.buf;
|
|
436
|
+
return t !== e && (n[t] = n[e], s = m(n[t])), this._entity_ids.pop(), this.length--, s;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Move an entity from src archetype into this archetype in a single pass.
|
|
440
|
+
* Combines add_entity + copy_shared_from + remove_entity(src).
|
|
441
|
+
* Uses a pre-computed transition map for branchless column copy.
|
|
442
|
+
* Writes dst_row to _move_result[0], swapped entity index to _move_result[1].
|
|
443
|
+
*/
|
|
444
|
+
move_entity_from(t, e, s, n) {
|
|
445
|
+
const r = this.length;
|
|
446
|
+
this._entity_ids.push(s);
|
|
447
|
+
const i = this._flat_columns, _ = t._flat_columns;
|
|
448
|
+
for (let o = 0; o < i.length; o++) {
|
|
449
|
+
const h = n[o];
|
|
450
|
+
i[o].push(h >= 0 ? _[h].buf[e] : 0);
|
|
451
|
+
}
|
|
452
|
+
this.length++;
|
|
453
|
+
const c = t.has_columns ? t.remove_entity(e) : t.remove_entity_tag(e);
|
|
454
|
+
f[0] = r, f[1] = c;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Move an entity from src into this archetype (tag-only: no columns to copy).
|
|
458
|
+
* Writes dst_row to _move_result[0], swapped entity index to _move_result[1].
|
|
459
|
+
*/
|
|
460
|
+
move_entity_from_tag(t, e, s) {
|
|
461
|
+
const n = this.length;
|
|
462
|
+
this._entity_ids.push(s), this.length++;
|
|
463
|
+
const r = t.remove_entity_tag(e);
|
|
464
|
+
f[0] = n, f[1] = r;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Bulk-move ALL entities from src into this archetype using TypedArray.set().
|
|
468
|
+
* Much faster than per-entity move_entity_from when the entire source is moving.
|
|
469
|
+
* After this call, src is empty. Returns the starting dst_row for the batch.
|
|
470
|
+
*/
|
|
471
|
+
bulk_move_all_from(t, e) {
|
|
472
|
+
const s = t.length;
|
|
473
|
+
if (s === 0) return this.length;
|
|
474
|
+
const n = this.length, r = this._flat_columns, i = t._flat_columns;
|
|
475
|
+
this._entity_ids.bulk_append(t._entity_ids.buf, 0, s);
|
|
476
|
+
for (let _ = 0; _ < r.length; _++) {
|
|
477
|
+
const c = e[_];
|
|
478
|
+
c >= 0 ? r[_].bulk_append(i[c].buf, 0, s) : r[_].bulk_append_zeroes(s);
|
|
479
|
+
}
|
|
480
|
+
this.length += s, t.length = 0, t._entity_ids.clear();
|
|
481
|
+
for (let _ = 0; _ < i.length; _++)
|
|
482
|
+
i[_].clear();
|
|
483
|
+
return n;
|
|
301
484
|
}
|
|
302
485
|
get_edge(t) {
|
|
303
486
|
return this.edges[t];
|
|
@@ -306,12 +489,25 @@ class K {
|
|
|
306
489
|
this.edges[t] = e;
|
|
307
490
|
}
|
|
308
491
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
492
|
+
const f = [0, y];
|
|
493
|
+
function M(l, t) {
|
|
494
|
+
const e = t._flat_columns, s = new Int16Array(e.length), n = t._column_ids, r = l._col_offset, i = t._col_offset, _ = t._field_count;
|
|
495
|
+
for (let c = 0; c < n.length; c++) {
|
|
496
|
+
const o = n[c], h = i[o], a = _[o], u = r[o];
|
|
497
|
+
if (u !== void 0)
|
|
498
|
+
for (let d = 0; d < a; d++)
|
|
499
|
+
s[h + d] = u + d;
|
|
500
|
+
else
|
|
501
|
+
for (let d = 0; d < a; d++)
|
|
502
|
+
s[h + d] = -1;
|
|
503
|
+
}
|
|
504
|
+
return s;
|
|
505
|
+
}
|
|
506
|
+
function K(l, t, e) {
|
|
507
|
+
const s = l.get(t);
|
|
508
|
+
s !== void 0 ? s.push(e) : l.set(t, [e]);
|
|
312
509
|
}
|
|
313
|
-
|
|
314
|
-
class J {
|
|
510
|
+
class At {
|
|
315
511
|
// --- Entity ID management ---
|
|
316
512
|
// Generational slot allocator: entity_generations[index] holds the current
|
|
317
513
|
// generation for that slot. Free indices are recycled via a stack.
|
|
@@ -320,7 +516,7 @@ class J {
|
|
|
320
516
|
entity_free_indices = [];
|
|
321
517
|
entity_alive_count = 0;
|
|
322
518
|
// --- Component metadata ---
|
|
323
|
-
// Parallel array indexed by ComponentID: field_names and
|
|
519
|
+
// Parallel array indexed by ComponentID: field_names, field_index, and field_types
|
|
324
520
|
// for building archetype column layouts.
|
|
325
521
|
component_metas = [];
|
|
326
522
|
component_count = 0;
|
|
@@ -328,6 +524,10 @@ class J {
|
|
|
328
524
|
// Parallel array indexed by EventID: each channel holds SoA columns + reader.
|
|
329
525
|
event_channels = [];
|
|
330
526
|
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;
|
|
331
531
|
// --- Archetype management ---
|
|
332
532
|
archetypes = [];
|
|
333
533
|
// Hash-bucketed lookup: BitSet.hash() → ArchetypeID[] for deduplication
|
|
@@ -353,18 +553,14 @@ class J {
|
|
|
353
553
|
pending_add_values = [];
|
|
354
554
|
pending_remove_ids = [];
|
|
355
555
|
pending_remove_defs = [];
|
|
356
|
-
|
|
357
|
-
|
|
556
|
+
initial_capacity;
|
|
557
|
+
constructor(t) {
|
|
558
|
+
this.initial_capacity = t ?? V, this.empty_archetype_id = this.arch_get_or_create_from_mask(new x());
|
|
358
559
|
}
|
|
359
560
|
// =======================================================
|
|
360
561
|
// Archetype graph
|
|
361
562
|
// =======================================================
|
|
362
563
|
arch_get(t) {
|
|
363
|
-
if (process.env.NODE_ENV !== "production" && (t < 0 || t >= this.archetypes.length))
|
|
364
|
-
throw new u(
|
|
365
|
-
d.ARCHETYPE_NOT_FOUND,
|
|
366
|
-
`Archetype with ID ${t} not found`
|
|
367
|
-
);
|
|
368
564
|
return this.archetypes[t];
|
|
369
565
|
}
|
|
370
566
|
/**
|
|
@@ -374,28 +570,29 @@ class J {
|
|
|
374
570
|
arch_get_or_create_from_mask(t) {
|
|
375
571
|
const e = t.hash(), s = this.archetype_map.get(e);
|
|
376
572
|
if (s !== void 0) {
|
|
377
|
-
for (let
|
|
378
|
-
if (this.archetypes[s[
|
|
379
|
-
return s[
|
|
573
|
+
for (let c = 0; c < s.length; c++)
|
|
574
|
+
if (this.archetypes[s[c]].mask.equals(t))
|
|
575
|
+
return s[c];
|
|
380
576
|
}
|
|
381
|
-
const n =
|
|
382
|
-
t.for_each((
|
|
383
|
-
const o =
|
|
384
|
-
|
|
577
|
+
const n = bt(this.next_archetype_id++), r = [];
|
|
578
|
+
t.for_each((c) => {
|
|
579
|
+
const o = c, h = this.component_metas[o];
|
|
580
|
+
h && h.field_names.length > 0 && r.push({
|
|
385
581
|
component_id: o,
|
|
386
|
-
field_names:
|
|
387
|
-
field_index:
|
|
582
|
+
field_names: h.field_names,
|
|
583
|
+
field_index: h.field_index,
|
|
584
|
+
field_types: h.field_types
|
|
388
585
|
});
|
|
389
586
|
});
|
|
390
|
-
const i = new
|
|
391
|
-
this.archetypes.push(i),
|
|
392
|
-
const o =
|
|
393
|
-
let
|
|
394
|
-
|
|
587
|
+
const i = new Tt(n, t, r, this.initial_capacity);
|
|
588
|
+
this.archetypes.push(i), K(this.archetype_map, e, n), t.for_each((c) => {
|
|
589
|
+
const o = c;
|
|
590
|
+
let h = this.component_index.get(o);
|
|
591
|
+
h || (h = /* @__PURE__ */ new Set(), this.component_index.set(o, h)), h.add(n);
|
|
395
592
|
});
|
|
396
593
|
const _ = this.registered_queries;
|
|
397
|
-
for (let
|
|
398
|
-
const o = _[
|
|
594
|
+
for (let c = 0; c < _.length; c++) {
|
|
595
|
+
const o = _[c];
|
|
399
596
|
i.matches(o.include_mask) && (!o.exclude_mask || !i.mask.overlaps(o.exclude_mask)) && (!o.any_of_mask || i.mask.overlaps(o.any_of_mask)) && o.result.push(i);
|
|
400
597
|
}
|
|
401
598
|
return n;
|
|
@@ -426,41 +623,44 @@ class J {
|
|
|
426
623
|
arch_cache_edge(t, e, s) {
|
|
427
624
|
const n = t.get_edge(s) ?? {
|
|
428
625
|
add: null,
|
|
429
|
-
remove: null
|
|
626
|
+
remove: null,
|
|
627
|
+
add_map: null,
|
|
628
|
+
remove_map: null
|
|
430
629
|
};
|
|
431
|
-
n.add = e.id, t.set_edge(s, n);
|
|
432
|
-
const r = e.get_edge(s) ?? {
|
|
433
|
-
|
|
630
|
+
n.add = e.id, n.add_map = M(t, e), t.set_edge(s, n);
|
|
631
|
+
const r = e.get_edge(s) ?? {
|
|
632
|
+
add: null,
|
|
633
|
+
remove: null,
|
|
634
|
+
add_map: null,
|
|
635
|
+
remove_map: null
|
|
636
|
+
};
|
|
637
|
+
r.remove = t.id, r.remove_map = M(e, t), e.set_edge(s, r);
|
|
434
638
|
}
|
|
435
639
|
// =======================================================
|
|
436
640
|
// Entity lifecycle
|
|
437
641
|
// =======================================================
|
|
438
642
|
create_entity() {
|
|
439
643
|
let t, e;
|
|
440
|
-
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] =
|
|
441
|
-
const s =
|
|
442
|
-
return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] =
|
|
644
|
+
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 = mt(t, e);
|
|
646
|
+
return this.entity_archetype[t] = this.empty_archetype_id, this.entity_row[t] = v, s;
|
|
443
647
|
}
|
|
444
648
|
/** Immediately destroy an entity, removing it from its archetype. */
|
|
445
649
|
destroy_entity(t) {
|
|
446
|
-
if (!this.is_alive(t))
|
|
447
|
-
if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
|
|
650
|
+
if (!this.is_alive(t))
|
|
448
651
|
return;
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
if (s !== m) {
|
|
652
|
+
const e = m(t), s = this.entity_row[e];
|
|
653
|
+
if (s !== v) {
|
|
452
654
|
const i = this.arch_get(this.entity_archetype[e]).remove_entity(s);
|
|
453
|
-
i !==
|
|
655
|
+
i !== y && (this.entity_row[i] = s);
|
|
454
656
|
}
|
|
455
|
-
this.entity_archetype[e] =
|
|
456
|
-
const n =
|
|
457
|
-
|
|
458
|
-
throw new u(d.EID_MAX_GEN_OVERFLOW);
|
|
459
|
-
this.entity_generations[e] = n + 1 & D, this.entity_free_indices.push(e), this.entity_alive_count--;
|
|
657
|
+
this.entity_archetype[e] = v, this.entity_row[e] = v;
|
|
658
|
+
const n = Y(t);
|
|
659
|
+
this.entity_generations[e] = n + 1 & X, this.entity_free_indices.push(e), this.entity_alive_count--;
|
|
460
660
|
}
|
|
461
661
|
is_alive(t) {
|
|
462
|
-
const e =
|
|
463
|
-
return e < this.entity_high_water && this.entity_generations[e] ===
|
|
662
|
+
const e = m(t);
|
|
663
|
+
return e < this.entity_high_water && this.entity_generations[e] === Y(t);
|
|
464
664
|
}
|
|
465
665
|
get entity_count() {
|
|
466
666
|
return this.entity_alive_count;
|
|
@@ -469,8 +669,6 @@ class J {
|
|
|
469
669
|
// Deferred destruction
|
|
470
670
|
// =======================================================
|
|
471
671
|
destroy_entity_deferred(t) {
|
|
472
|
-
if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
|
|
473
|
-
throw new u(d.ENTITY_NOT_ALIVE);
|
|
474
672
|
this.pending_destroy.push(t);
|
|
475
673
|
}
|
|
476
674
|
/** Flush all buffered entity destructions in batch. */
|
|
@@ -479,16 +677,14 @@ class J {
|
|
|
479
677
|
if (t.length === 0) return;
|
|
480
678
|
const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, r = this.archetypes, i = this.entity_high_water;
|
|
481
679
|
for (let _ = 0; _ < t.length; _++) {
|
|
482
|
-
const
|
|
483
|
-
if (o >= i || n[o] !==
|
|
484
|
-
const
|
|
485
|
-
if (
|
|
486
|
-
const
|
|
487
|
-
|
|
680
|
+
const c = t[_], o = c & F, h = c >> P;
|
|
681
|
+
if (o >= i || n[o] !== h) continue;
|
|
682
|
+
const a = s[o];
|
|
683
|
+
if (a !== v) {
|
|
684
|
+
const u = r[e[o]], d = u.has_columns ? u.remove_entity(a) : u.remove_entity_tag(a);
|
|
685
|
+
d !== y && (s[d] = a);
|
|
488
686
|
}
|
|
489
|
-
|
|
490
|
-
throw new u(d.EID_MAX_GEN_OVERFLOW);
|
|
491
|
-
n[o] = c + 1 & D, this.entity_free_indices.push(o), this.entity_alive_count--;
|
|
687
|
+
e[o] = v, s[o] = v, n[o] = h + 1 & X, this.entity_free_indices.push(o), this.entity_alive_count--;
|
|
492
688
|
}
|
|
493
689
|
t.length = 0;
|
|
494
690
|
}
|
|
@@ -496,13 +692,9 @@ class J {
|
|
|
496
692
|
return this.pending_destroy.length;
|
|
497
693
|
}
|
|
498
694
|
add_component_deferred(t, e, s) {
|
|
499
|
-
|
|
500
|
-
throw new u(d.ENTITY_NOT_ALIVE);
|
|
501
|
-
this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? V);
|
|
695
|
+
this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? D);
|
|
502
696
|
}
|
|
503
697
|
remove_component_deferred(t, e) {
|
|
504
|
-
if (process.env.NODE_ENV !== "production" && !this.is_alive(t))
|
|
505
|
-
throw new u(d.ENTITY_NOT_ALIVE);
|
|
506
698
|
this.pending_remove_ids.push(t), this.pending_remove_defs.push(e);
|
|
507
699
|
}
|
|
508
700
|
flush_structural() {
|
|
@@ -510,37 +702,47 @@ class J {
|
|
|
510
702
|
}
|
|
511
703
|
/** Batch-apply all deferred component additions. */
|
|
512
704
|
_flush_adds() {
|
|
513
|
-
const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length, r = this.entity_archetype, i = this.entity_row, _ = this.entity_generations,
|
|
514
|
-
for (let
|
|
515
|
-
const
|
|
516
|
-
if (
|
|
517
|
-
const T = r[
|
|
518
|
-
if (
|
|
519
|
-
o[
|
|
705
|
+
const t = this.pending_add_ids, e = this.pending_add_defs, s = this.pending_add_values, n = t.length, r = this.entity_archetype, i = this.entity_row, _ = this.entity_generations, c = this.archetypes, o = this.component_metas, h = this.entity_high_water;
|
|
706
|
+
for (let a = 0; a < n; a++) {
|
|
707
|
+
const u = t[a], d = u & F, g = u >> P;
|
|
708
|
+
if (d >= h || _[d] !== g) continue;
|
|
709
|
+
const T = r[d], p = e[a], w = c[T];
|
|
710
|
+
if (w.mask.has(p)) {
|
|
711
|
+
o[p].field_names.length > 0 && w.write_fields(i[d], p, s[a]);
|
|
520
712
|
continue;
|
|
521
713
|
}
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
714
|
+
const S = this.arch_resolve_add(T, p), E = c[S], O = i[d], L = !E.has_columns && !w.has_columns;
|
|
715
|
+
let U;
|
|
716
|
+
if (O !== v) {
|
|
717
|
+
if (L)
|
|
718
|
+
E.move_entity_from_tag(w, O, u);
|
|
719
|
+
else {
|
|
720
|
+
const $ = w.get_edge(p);
|
|
721
|
+
E.move_entity_from(w, O, u, $.add_map);
|
|
722
|
+
}
|
|
723
|
+
U = f[0], f[1] !== y && (i[f[1]] = O);
|
|
724
|
+
} else
|
|
725
|
+
U = L ? E.add_entity_tag(u) : E.add_entity(u);
|
|
726
|
+
o[p].field_names.length > 0 && E.write_fields(U, p, s[a]), r[d] = S, i[d] = U;
|
|
529
727
|
}
|
|
530
728
|
t.length = 0, e.length = 0, s.length = 0;
|
|
531
729
|
}
|
|
532
730
|
/** Batch-apply all deferred component removals. */
|
|
533
731
|
_flush_removes() {
|
|
534
|
-
const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype, r = this.entity_row, i = this.entity_generations, _ = this.archetypes,
|
|
732
|
+
const t = this.pending_remove_ids, e = this.pending_remove_defs, s = t.length, n = this.entity_archetype, r = this.entity_row, i = this.entity_generations, _ = this.archetypes, c = this.entity_high_water;
|
|
535
733
|
for (let o = 0; o < s; o++) {
|
|
536
|
-
const
|
|
537
|
-
if (
|
|
538
|
-
const
|
|
539
|
-
if (!T.mask.has(
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
734
|
+
const h = t[o], a = h & F, u = h >> P;
|
|
735
|
+
if (a >= c || i[a] !== u) continue;
|
|
736
|
+
const d = n[a], g = e[o], T = _[d];
|
|
737
|
+
if (!T.mask.has(g)) continue;
|
|
738
|
+
const p = this.arch_resolve_remove(d, g), w = _[p], S = r[a];
|
|
739
|
+
if (!w.has_columns && !T.has_columns)
|
|
740
|
+
w.move_entity_from_tag(T, S, h);
|
|
741
|
+
else {
|
|
742
|
+
const O = T.get_edge(g);
|
|
743
|
+
w.move_entity_from(T, S, h, O.remove_map);
|
|
744
|
+
}
|
|
745
|
+
f[1] !== y && (r[f[1]] = S), n[a] = p, r[a] = f[0];
|
|
544
746
|
}
|
|
545
747
|
t.length = 0, e.length = 0;
|
|
546
748
|
}
|
|
@@ -551,17 +753,15 @@ class J {
|
|
|
551
753
|
// Component registration
|
|
552
754
|
// =======================================================
|
|
553
755
|
register_component(t) {
|
|
554
|
-
const e =
|
|
555
|
-
for (let
|
|
556
|
-
|
|
557
|
-
return this.component_metas.push({ field_names: s, field_index: n }), e;
|
|
756
|
+
const e = yt(this.component_count++), s = Object.keys(t), n = new Array(s.length), r = /* @__PURE__ */ Object.create(null);
|
|
757
|
+
for (let i = 0; i < s.length; i++)
|
|
758
|
+
r[s[i]] = i, n[i] = t[s[i]];
|
|
759
|
+
return this.component_metas.push({ field_names: s, field_index: r, field_types: n }), e;
|
|
558
760
|
}
|
|
559
761
|
add_component(t, e, s) {
|
|
560
|
-
if (!this.is_alive(t))
|
|
561
|
-
if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
|
|
762
|
+
if (!this.is_alive(t))
|
|
562
763
|
return;
|
|
563
|
-
|
|
564
|
-
const n = y(t), r = this.entity_archetype[n], i = this.arch_get(r);
|
|
764
|
+
const n = m(t), r = this.entity_archetype[n], i = this.arch_get(r);
|
|
565
765
|
if (i.has_component(e)) {
|
|
566
766
|
i.write_fields(
|
|
567
767
|
this.entity_row[n],
|
|
@@ -573,25 +773,24 @@ class J {
|
|
|
573
773
|
const _ = this.arch_resolve_add(
|
|
574
774
|
r,
|
|
575
775
|
e
|
|
576
|
-
),
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
|
|
776
|
+
), c = this.arch_get(_), o = this.entity_row[n];
|
|
777
|
+
let h;
|
|
778
|
+
if (o !== v) {
|
|
779
|
+
const a = i.get_edge(e);
|
|
780
|
+
!c.has_columns && !i.has_columns ? c.move_entity_from_tag(i, o, t) : c.move_entity_from(i, o, t, a.add_map), h = f[0], f[1] !== y && (this.entity_row[f[1]] = o);
|
|
781
|
+
} else
|
|
782
|
+
h = c.has_columns ? c.add_entity(t) : c.add_entity_tag(t);
|
|
783
|
+
c.write_fields(
|
|
784
|
+
h,
|
|
584
785
|
e,
|
|
585
786
|
s
|
|
586
|
-
), this.entity_archetype[n] = _, this.entity_row[n] =
|
|
787
|
+
), this.entity_archetype[n] = _, this.entity_row[n] = h;
|
|
587
788
|
}
|
|
588
789
|
/** Add multiple components in one transition (resolves final archetype, then moves once). */
|
|
589
790
|
add_components(t, e) {
|
|
590
|
-
if (!this.is_alive(t))
|
|
591
|
-
if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
|
|
791
|
+
if (!this.is_alive(t))
|
|
592
792
|
return;
|
|
593
|
-
|
|
594
|
-
const s = y(t), n = this.entity_archetype[s];
|
|
793
|
+
const s = m(t), n = this.entity_archetype[s];
|
|
595
794
|
let r = n;
|
|
596
795
|
for (let i = 0; i < e.length; i++)
|
|
597
796
|
r = this.arch_resolve_add(
|
|
@@ -599,83 +798,107 @@ class J {
|
|
|
599
798
|
e[i].def
|
|
600
799
|
);
|
|
601
800
|
if (r !== n) {
|
|
602
|
-
const i = this.arch_get(n), _ = this.arch_get(r),
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const
|
|
606
|
-
c
|
|
607
|
-
}
|
|
608
|
-
|
|
801
|
+
const i = this.arch_get(n), _ = this.arch_get(r), c = this.entity_row[s];
|
|
802
|
+
let o;
|
|
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);
|
|
806
|
+
} else
|
|
807
|
+
o = _.add_entity(t);
|
|
808
|
+
for (let h = 0; h < e.length; h++)
|
|
609
809
|
_.write_fields(
|
|
610
810
|
o,
|
|
611
|
-
e[
|
|
612
|
-
e[
|
|
811
|
+
e[h].def,
|
|
812
|
+
e[h].values ?? D
|
|
613
813
|
);
|
|
614
814
|
this.entity_archetype[s] = r, this.entity_row[s] = o;
|
|
615
815
|
} else {
|
|
616
816
|
const i = this.arch_get(n), _ = this.entity_row[s];
|
|
617
|
-
for (let
|
|
817
|
+
for (let c = 0; c < e.length; c++)
|
|
618
818
|
i.write_fields(
|
|
619
819
|
_,
|
|
620
|
-
e[
|
|
621
|
-
e[
|
|
820
|
+
e[c].def,
|
|
821
|
+
e[c].values ?? D
|
|
622
822
|
);
|
|
623
823
|
}
|
|
624
824
|
}
|
|
625
825
|
remove_component(t, e) {
|
|
626
|
-
if (!this.is_alive(t))
|
|
627
|
-
if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
|
|
826
|
+
if (!this.is_alive(t))
|
|
628
827
|
return;
|
|
629
|
-
|
|
630
|
-
const s = y(t), n = this.entity_archetype[s], r = this.arch_get(n);
|
|
828
|
+
const s = m(t), n = this.entity_archetype[s], r = this.arch_get(n);
|
|
631
829
|
if (!r.has_component(e)) return;
|
|
632
830
|
const i = this.arch_resolve_remove(
|
|
633
831
|
n,
|
|
634
832
|
e
|
|
635
|
-
), _ = this.arch_get(i),
|
|
636
|
-
_.
|
|
637
|
-
const c = r.remove_entity(h);
|
|
638
|
-
c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = i, this.entity_row[s] = o;
|
|
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];
|
|
639
835
|
}
|
|
640
836
|
/** Remove multiple components in one transition (resolves final archetype, then moves once). */
|
|
641
837
|
remove_components(t, e) {
|
|
642
|
-
if (!this.is_alive(t))
|
|
643
|
-
if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
|
|
838
|
+
if (!this.is_alive(t))
|
|
644
839
|
return;
|
|
645
|
-
|
|
646
|
-
const s = y(t), n = this.entity_archetype[s];
|
|
840
|
+
const s = m(t), n = this.entity_archetype[s];
|
|
647
841
|
let r = n;
|
|
648
|
-
for (let
|
|
842
|
+
for (let h = 0; h < e.length; h++)
|
|
649
843
|
r = this.arch_resolve_remove(
|
|
650
844
|
r,
|
|
651
|
-
e[
|
|
845
|
+
e[h]
|
|
652
846
|
);
|
|
653
847
|
if (r === n) return;
|
|
654
|
-
const i = this.arch_get(n), _ = this.arch_get(r),
|
|
655
|
-
_.
|
|
656
|
-
const c = i.remove_entity(h);
|
|
657
|
-
c !== -1 && (this.entity_row[c] = h), this.entity_archetype[s] = r, this.entity_row[s] = o;
|
|
848
|
+
const i = this.arch_get(n), _ = this.arch_get(r), c = this.entity_row[s], o = M(i, _);
|
|
849
|
+
_.move_entity_from(i, c, t, o), f[1] !== y && (this.entity_row[f[1]] = c), this.entity_archetype[s] = r, this.entity_row[s] = f[0];
|
|
658
850
|
}
|
|
659
851
|
has_component(t, e) {
|
|
660
|
-
if (!this.is_alive(t))
|
|
661
|
-
if (process.env.NODE_ENV !== "production") throw new u(d.ENTITY_NOT_ALIVE);
|
|
852
|
+
if (!this.is_alive(t))
|
|
662
853
|
return !1;
|
|
663
|
-
|
|
664
|
-
const s = y(t);
|
|
854
|
+
const s = m(t);
|
|
665
855
|
return this.arch_get(
|
|
666
856
|
this.entity_archetype[s]
|
|
667
857
|
).has_component(e);
|
|
668
858
|
}
|
|
859
|
+
/**
|
|
860
|
+
* Bulk add a component to ALL entities in the given archetype.
|
|
861
|
+
* Uses TypedArray.set() for O(columns) instead of O(N×columns).
|
|
862
|
+
* The archetype must not already contain this component.
|
|
863
|
+
*/
|
|
864
|
+
batch_add_component(t, e, s) {
|
|
865
|
+
if (t.length === 0) return;
|
|
866
|
+
const n = e;
|
|
867
|
+
if (t.mask.has(n)) return;
|
|
868
|
+
const r = this.arch_resolve_add(t.id, n), i = this.arch_get(r), _ = t.get_edge(n), c = t.length, o = this.entity_archetype, h = this.entity_row, a = i.bulk_move_all_from(t, _.add_map);
|
|
869
|
+
for (let d = 0; d < c; d++) {
|
|
870
|
+
const g = m(i.entity_ids[a + d]);
|
|
871
|
+
o[g] = r, h[g] = a + d;
|
|
872
|
+
}
|
|
873
|
+
if (this.component_metas[n].field_names.length > 0 && s)
|
|
874
|
+
for (let d = 0; d < c; d++)
|
|
875
|
+
i.write_fields(a + d, n, s);
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Bulk remove a component from ALL entities in the given archetype.
|
|
879
|
+
* Uses TypedArray.set() for O(columns) instead of O(N×columns).
|
|
880
|
+
* The archetype must contain this component.
|
|
881
|
+
*/
|
|
882
|
+
batch_remove_component(t, e) {
|
|
883
|
+
if (t.length === 0) return;
|
|
884
|
+
const s = e;
|
|
885
|
+
if (!t.mask.has(s)) return;
|
|
886
|
+
const n = this.arch_resolve_remove(t.id, s), r = this.arch_get(n), i = t.get_edge(s), _ = t.length, c = r.bulk_move_all_from(t, i.remove_map), o = this.entity_archetype, h = this.entity_row;
|
|
887
|
+
for (let a = 0; a < _; a++) {
|
|
888
|
+
const u = m(r.entity_ids[c + a]);
|
|
889
|
+
o[u] = n, h[u] = c + a;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
669
892
|
// =======================================================
|
|
670
893
|
// Direct data access (used by SystemContext)
|
|
671
894
|
// =======================================================
|
|
672
895
|
get_entity_archetype(t) {
|
|
673
896
|
return this.arch_get(
|
|
674
|
-
this.entity_archetype[
|
|
897
|
+
this.entity_archetype[m(t)]
|
|
675
898
|
);
|
|
676
899
|
}
|
|
677
900
|
get_entity_row(t) {
|
|
678
|
-
return this.entity_row[
|
|
901
|
+
return this.entity_row[m(t)];
|
|
679
902
|
}
|
|
680
903
|
// =======================================================
|
|
681
904
|
// Query support
|
|
@@ -699,28 +922,28 @@ class J {
|
|
|
699
922
|
);
|
|
700
923
|
let i, _ = !1;
|
|
701
924
|
for (let o = 0; o < n.length; o++) {
|
|
702
|
-
let
|
|
703
|
-
if (
|
|
704
|
-
const
|
|
705
|
-
for (;
|
|
706
|
-
const
|
|
707
|
-
|
|
708
|
-
const
|
|
709
|
-
if (!
|
|
925
|
+
let h = n[o];
|
|
926
|
+
if (h === 0) continue;
|
|
927
|
+
const a = o << k;
|
|
928
|
+
for (; h !== 0; ) {
|
|
929
|
+
const u = h & -h >>> 0, d = a + (I - Math.clz32(u));
|
|
930
|
+
h ^= u;
|
|
931
|
+
const g = this.component_index.get(d);
|
|
932
|
+
if (!g || g.size === 0) {
|
|
710
933
|
_ = !0;
|
|
711
934
|
break;
|
|
712
935
|
}
|
|
713
|
-
(!i ||
|
|
936
|
+
(!i || g.size < i.size) && (i = g);
|
|
714
937
|
}
|
|
715
938
|
if (_) break;
|
|
716
939
|
}
|
|
717
940
|
if (_ || !i) return [];
|
|
718
|
-
const
|
|
941
|
+
const c = [];
|
|
719
942
|
for (const o of i) {
|
|
720
|
-
const
|
|
721
|
-
|
|
943
|
+
const h = this.arch_get(o);
|
|
944
|
+
h.matches(t) && (!e || !h.mask.overlaps(e)) && (!s || h.mask.overlaps(s)) && c.push(h);
|
|
722
945
|
}
|
|
723
|
-
return
|
|
946
|
+
return c;
|
|
724
947
|
}
|
|
725
948
|
/**
|
|
726
949
|
* Register a live query. Returns a mutable Archetype[] that this Store will
|
|
@@ -746,7 +969,7 @@ class J {
|
|
|
746
969
|
// Event channels
|
|
747
970
|
// =======================================================
|
|
748
971
|
register_event(t) {
|
|
749
|
-
const e =
|
|
972
|
+
const e = pt(this.event_count++), s = new wt(t);
|
|
750
973
|
return this.event_channels.push(s), e;
|
|
751
974
|
}
|
|
752
975
|
emit_event(t, e) {
|
|
@@ -763,40 +986,47 @@ class J {
|
|
|
763
986
|
for (let e = 0; e < t.length; e++)
|
|
764
987
|
t[e].clear();
|
|
765
988
|
}
|
|
989
|
+
// =======================================================
|
|
990
|
+
// Resource channels
|
|
991
|
+
// =======================================================
|
|
992
|
+
register_resource(t, e) {
|
|
993
|
+
const s = vt(this.resource_count++), n = new xt(t, e);
|
|
994
|
+
return this.resource_channels.push(n), s;
|
|
995
|
+
}
|
|
996
|
+
get_resource_reader(t) {
|
|
997
|
+
return this.resource_channels[t].reader;
|
|
998
|
+
}
|
|
999
|
+
get_resource_channel(t) {
|
|
1000
|
+
return this.resource_channels[t];
|
|
1001
|
+
}
|
|
766
1002
|
}
|
|
767
|
-
var
|
|
768
|
-
const
|
|
1003
|
+
var Et = /* @__PURE__ */ ((l) => (l.PRE_STARTUP = "PRE_STARTUP", l.STARTUP = "STARTUP", l.POST_STARTUP = "POST_STARTUP", l.FIXED_UPDATE = "FIXED_UPDATE", l.PRE_UPDATE = "PRE_UPDATE", l.UPDATE = "UPDATE", l.POST_UPDATE = "POST_UPDATE", l))(Et || {});
|
|
1004
|
+
const q = [
|
|
769
1005
|
"PRE_STARTUP",
|
|
770
1006
|
"STARTUP",
|
|
771
1007
|
"POST_STARTUP"
|
|
772
1008
|
/* POST_STARTUP */
|
|
773
|
-
],
|
|
1009
|
+
], G = [
|
|
774
1010
|
"PRE_UPDATE",
|
|
775
1011
|
"UPDATE",
|
|
776
1012
|
"POST_UPDATE"
|
|
777
1013
|
/* POST_UPDATE */
|
|
778
1014
|
];
|
|
779
|
-
class
|
|
1015
|
+
class kt {
|
|
780
1016
|
label_systems = /* @__PURE__ */ new Map();
|
|
781
1017
|
sorted_cache = /* @__PURE__ */ new Map();
|
|
782
1018
|
system_index = /* @__PURE__ */ new Map();
|
|
783
1019
|
next_insertion_order = 0;
|
|
784
1020
|
constructor() {
|
|
785
|
-
for (let t = 0; t <
|
|
786
|
-
this.label_systems.set(
|
|
1021
|
+
for (let t = 0; t < q.length; t++)
|
|
1022
|
+
this.label_systems.set(q[t], []);
|
|
787
1023
|
this.label_systems.set("FIXED_UPDATE", []);
|
|
788
|
-
for (let t = 0; t <
|
|
789
|
-
this.label_systems.set(
|
|
1024
|
+
for (let t = 0; t < G.length; t++)
|
|
1025
|
+
this.label_systems.set(G[t], []);
|
|
790
1026
|
}
|
|
791
1027
|
add_systems(t, ...e) {
|
|
792
1028
|
for (const s of e) {
|
|
793
|
-
const n = "system" in s ? s.system : s, r = "system" in s ? s.ordering : void 0
|
|
794
|
-
if (process.env.NODE_ENV !== "production" && this.system_index.has(n))
|
|
795
|
-
throw new u(
|
|
796
|
-
d.DUPLICATE_SYSTEM,
|
|
797
|
-
`System ${n.id} is already scheduled`
|
|
798
|
-
);
|
|
799
|
-
const i = {
|
|
1029
|
+
const n = "system" in s ? s.system : s, r = "system" in s ? s.ordering : void 0, i = {
|
|
800
1030
|
descriptor: n,
|
|
801
1031
|
insertion_order: this.next_insertion_order++,
|
|
802
1032
|
before: new Set(r?.before ?? []),
|
|
@@ -818,11 +1048,11 @@ class H {
|
|
|
818
1048
|
this.system_index.delete(t), this.sorted_cache.delete(e);
|
|
819
1049
|
}
|
|
820
1050
|
run_startup(t) {
|
|
821
|
-
for (const e of
|
|
822
|
-
this.run_label(e, t,
|
|
1051
|
+
for (const e of q)
|
|
1052
|
+
this.run_label(e, t, it);
|
|
823
1053
|
}
|
|
824
1054
|
run_update(t, e) {
|
|
825
|
-
for (const s of
|
|
1055
|
+
for (const s of G)
|
|
826
1056
|
this.run_label(s, t, e);
|
|
827
1057
|
}
|
|
828
1058
|
run_fixed_update(t, e) {
|
|
@@ -871,51 +1101,72 @@ class H {
|
|
|
871
1101
|
for (const o of t)
|
|
872
1102
|
s.set(o.descriptor, /* @__PURE__ */ new Set()), n.set(o.descriptor, 0), r.set(o.descriptor, o.insertion_order), i.add(o.descriptor);
|
|
873
1103
|
for (const o of t) {
|
|
874
|
-
for (const
|
|
875
|
-
i.has(
|
|
876
|
-
for (const
|
|
877
|
-
i.has(
|
|
1104
|
+
for (const h of o.before)
|
|
1105
|
+
i.has(h) && (s.get(o.descriptor).add(h), n.set(h, n.get(h) + 1));
|
|
1106
|
+
for (const h of o.after)
|
|
1107
|
+
i.has(h) && (s.get(h).add(o.descriptor), n.set(o.descriptor, n.get(o.descriptor) + 1));
|
|
878
1108
|
}
|
|
879
1109
|
let _ = [];
|
|
880
1110
|
for (const o of t)
|
|
881
1111
|
n.get(o.descriptor) === 0 && _.push(o.descriptor);
|
|
882
|
-
_.sort((o,
|
|
883
|
-
const
|
|
1112
|
+
_.sort((o, h) => r.get(h) - r.get(o));
|
|
1113
|
+
const c = [];
|
|
884
1114
|
for (; _.length > 0; ) {
|
|
885
1115
|
const o = _.pop();
|
|
886
|
-
|
|
887
|
-
for (const
|
|
888
|
-
const
|
|
889
|
-
n.set(
|
|
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);
|
|
890
1120
|
}
|
|
891
|
-
_.sort((
|
|
1121
|
+
_.sort((h, a) => r.get(a) - r.get(h));
|
|
892
1122
|
}
|
|
893
|
-
if (
|
|
894
|
-
const o = new Set(
|
|
895
|
-
throw new
|
|
896
|
-
|
|
897
|
-
`Circular system dependency detected in ${e}: [${
|
|
1123
|
+
if (c.length !== t.length) {
|
|
1124
|
+
const o = new Set(c), h = t.filter((a) => !o.has(a.descriptor)).map((a) => a.descriptor.name ?? `system_${a.descriptor.id}`);
|
|
1125
|
+
throw new Q(
|
|
1126
|
+
z.CIRCULAR_SYSTEM_DEPENDENCY,
|
|
1127
|
+
`Circular system dependency detected in ${e}: [${h.join(", ")}]`
|
|
898
1128
|
);
|
|
899
1129
|
}
|
|
900
|
-
return
|
|
1130
|
+
return c;
|
|
901
1131
|
}
|
|
902
1132
|
}
|
|
903
|
-
const
|
|
904
|
-
|
|
1133
|
+
const W = /* @__PURE__ */ new WeakMap();
|
|
1134
|
+
function It(l, t) {
|
|
1135
|
+
let e = W.get(l);
|
|
1136
|
+
if (!e) {
|
|
1137
|
+
e = /* @__PURE__ */ Object.create(null);
|
|
1138
|
+
const { field_names: r } = l.layout;
|
|
1139
|
+
for (let i = 0; i < r.length; i++) {
|
|
1140
|
+
const _ = i;
|
|
1141
|
+
Object.defineProperty(e, r[i], {
|
|
1142
|
+
get() {
|
|
1143
|
+
return this._columns[_][this._row];
|
|
1144
|
+
},
|
|
1145
|
+
set(c) {
|
|
1146
|
+
this._columns[_][this._row] = c;
|
|
1147
|
+
},
|
|
1148
|
+
enumerable: !0,
|
|
1149
|
+
configurable: !1
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
W.set(l, e);
|
|
1153
|
+
}
|
|
1154
|
+
const s = Object.create(e), n = new Array(l.columns.length);
|
|
1155
|
+
for (let r = 0; r < l.columns.length; r++) n[r] = l.columns[r].buf;
|
|
1156
|
+
return s._columns = n, s._row = t, s;
|
|
1157
|
+
}
|
|
1158
|
+
class Pt {
|
|
905
1159
|
_archetypes;
|
|
906
1160
|
_defs;
|
|
907
1161
|
_resolver;
|
|
908
1162
|
_include;
|
|
909
1163
|
_exclude;
|
|
910
1164
|
_any_of;
|
|
911
|
-
// Pre-allocated args buffer for each() — avoids allocating a new array per
|
|
912
|
-
// archetype. Holds [columnGroup0, columnGroup1, ..., entityCount].
|
|
913
|
-
_args_buf;
|
|
914
1165
|
constructor(t, e, s, n, r, i) {
|
|
915
|
-
this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = r, this._any_of = i
|
|
1166
|
+
this._archetypes = t, this._defs = e, this._resolver = s, this._include = n, this._exclude = r, this._any_of = i;
|
|
916
1167
|
}
|
|
917
1168
|
/** Number of matching archetypes (including empty ones). */
|
|
918
|
-
get
|
|
1169
|
+
get archetype_count() {
|
|
919
1170
|
return this._archetypes.length;
|
|
920
1171
|
}
|
|
921
1172
|
/** Total entity count across all matching archetypes. */
|
|
@@ -934,22 +1185,6 @@ class et {
|
|
|
934
1185
|
for (let e = 0; e < t.length; e++)
|
|
935
1186
|
t[e].entity_count > 0 && (yield t[e]);
|
|
936
1187
|
}
|
|
937
|
-
/**
|
|
938
|
-
* Typed per-archetype iteration. Calls fn once per non-empty archetype
|
|
939
|
-
* with column groups for each queried component, plus the entity count.
|
|
940
|
-
* The system is responsible for the inner loop over entities.
|
|
941
|
-
*/
|
|
942
|
-
each(t) {
|
|
943
|
-
const e = this._archetypes, s = this._defs, n = this._args_buf;
|
|
944
|
-
for (let r = 0; r < e.length; r++) {
|
|
945
|
-
const i = e[r], _ = i.entity_count;
|
|
946
|
-
if (_ !== 0) {
|
|
947
|
-
for (let h = 0; h < s.length; h++)
|
|
948
|
-
n[h] = i.get_column_group(s[h]);
|
|
949
|
-
n[s.length] = _, t.apply(null, n);
|
|
950
|
-
}
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
1188
|
/** Extend required component set. Returns a new (cached) Query. */
|
|
954
1189
|
and(...t) {
|
|
955
1190
|
const e = this._include.copy(), s = this._defs.slice();
|
|
@@ -964,7 +1199,7 @@ class et {
|
|
|
964
1199
|
}
|
|
965
1200
|
/** Exclude archetypes that have any of these components. */
|
|
966
1201
|
not(...t) {
|
|
967
|
-
const e = this._exclude ? this._exclude.copy() : new
|
|
1202
|
+
const e = this._exclude ? this._exclude.copy() : new x();
|
|
968
1203
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
969
1204
|
return this._resolver._resolve_query(
|
|
970
1205
|
this._include,
|
|
@@ -974,8 +1209,8 @@ class et {
|
|
|
974
1209
|
);
|
|
975
1210
|
}
|
|
976
1211
|
/** Require at least one of these components. */
|
|
977
|
-
|
|
978
|
-
const e = this._any_of ? this._any_of.copy() : new
|
|
1212
|
+
any_of(...t) {
|
|
1213
|
+
const e = this._any_of ? this._any_of.copy() : new x();
|
|
979
1214
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
980
1215
|
return this._resolver._resolve_query(
|
|
981
1216
|
this._include,
|
|
@@ -985,17 +1220,17 @@ class et {
|
|
|
985
1220
|
);
|
|
986
1221
|
}
|
|
987
1222
|
}
|
|
988
|
-
class
|
|
1223
|
+
class St {
|
|
989
1224
|
constructor(t) {
|
|
990
1225
|
this._resolver = t;
|
|
991
1226
|
}
|
|
992
1227
|
every(...t) {
|
|
993
|
-
const e = new
|
|
1228
|
+
const e = new x();
|
|
994
1229
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
995
1230
|
return this._resolver._resolve_query(e, null, null, t);
|
|
996
1231
|
}
|
|
997
1232
|
}
|
|
998
|
-
class
|
|
1233
|
+
class Ot {
|
|
999
1234
|
store;
|
|
1000
1235
|
constructor(t) {
|
|
1001
1236
|
this.store = t;
|
|
@@ -1004,22 +1239,24 @@ class nt {
|
|
|
1004
1239
|
return this.store.create_entity();
|
|
1005
1240
|
}
|
|
1006
1241
|
get_field(t, e, s) {
|
|
1007
|
-
const n = this.store.get_entity_archetype(
|
|
1008
|
-
return n.read_field(r,
|
|
1242
|
+
const n = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t);
|
|
1243
|
+
return n.read_field(r, e, s);
|
|
1009
1244
|
}
|
|
1010
1245
|
set_field(t, e, s, n) {
|
|
1011
|
-
const r = this.store.get_entity_archetype(
|
|
1246
|
+
const r = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t), _ = r.get_column(e, s);
|
|
1012
1247
|
_[i] = n;
|
|
1013
1248
|
}
|
|
1249
|
+
/** Create a cached component reference for a single entity. See ref.ts. */
|
|
1250
|
+
ref(t, e) {
|
|
1251
|
+
const s = this.store.get_entity_archetype(e), n = this.store.get_entity_row(e);
|
|
1252
|
+
return It(s.column_groups[t], n);
|
|
1253
|
+
}
|
|
1014
1254
|
/** Buffer an entity for deferred destruction (applied at phase flush). */
|
|
1015
1255
|
destroy_entity(t) {
|
|
1016
1256
|
return this.store.destroy_entity_deferred(t), this;
|
|
1017
1257
|
}
|
|
1018
|
-
flush_destroyed() {
|
|
1019
|
-
this.store.flush_destroyed();
|
|
1020
|
-
}
|
|
1021
1258
|
add_component(t, e, s) {
|
|
1022
|
-
return this.store.add_component_deferred(t, e, s ??
|
|
1259
|
+
return this.store.add_component_deferred(t, e, s ?? D), this;
|
|
1023
1260
|
}
|
|
1024
1261
|
remove_component(t, e) {
|
|
1025
1262
|
return this.store.remove_component_deferred(t, e), this;
|
|
@@ -1034,13 +1271,20 @@ class nt {
|
|
|
1034
1271
|
read(t) {
|
|
1035
1272
|
return this.store.get_event_reader(t);
|
|
1036
1273
|
}
|
|
1274
|
+
// =======================================================
|
|
1275
|
+
// Resources
|
|
1276
|
+
// =======================================================
|
|
1277
|
+
resource(t) {
|
|
1278
|
+
return this.store.get_resource_reader(t);
|
|
1279
|
+
}
|
|
1280
|
+
set_resource(t, e) {
|
|
1281
|
+
this.store.get_resource_channel(t).write(e);
|
|
1282
|
+
}
|
|
1037
1283
|
}
|
|
1038
|
-
const
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
), it = Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
1043
|
-
class ot {
|
|
1284
|
+
const Dt = (l) => N(
|
|
1285
|
+
l
|
|
1286
|
+
);
|
|
1287
|
+
class Nt {
|
|
1044
1288
|
store;
|
|
1045
1289
|
schedule;
|
|
1046
1290
|
ctx;
|
|
@@ -1054,9 +1298,9 @@ class ot {
|
|
|
1054
1298
|
// Multiple queries can share the same hash (collision), so each bucket is an array.
|
|
1055
1299
|
query_cache = /* @__PURE__ */ new Map();
|
|
1056
1300
|
// Reusable BitSet for building query masks — avoids allocation per query() call
|
|
1057
|
-
scratch_mask = new
|
|
1301
|
+
scratch_mask = new x();
|
|
1058
1302
|
constructor(t) {
|
|
1059
|
-
this.store = new
|
|
1303
|
+
this.store = new At(t?.initial_capacity), this.schedule = new kt(), this.ctx = new Ot(this.store), this._fixed_timestep = t?.fixed_timestep ?? nt, this._max_fixed_steps = t?.max_fixed_steps ?? rt;
|
|
1060
1304
|
}
|
|
1061
1305
|
get fixed_timestep() {
|
|
1062
1306
|
return this._fixed_timestep;
|
|
@@ -1067,11 +1311,17 @@ class ot {
|
|
|
1067
1311
|
get fixed_alpha() {
|
|
1068
1312
|
return this._accumulator / this._fixed_timestep;
|
|
1069
1313
|
}
|
|
1070
|
-
|
|
1314
|
+
// Implementation
|
|
1315
|
+
register_component(t, e) {
|
|
1316
|
+
if (Array.isArray(t)) {
|
|
1317
|
+
const s = e ?? "f64", n = /* @__PURE__ */ Object.create(null);
|
|
1318
|
+
for (const r of t) n[r] = s;
|
|
1319
|
+
return this.store.register_component(n);
|
|
1320
|
+
}
|
|
1071
1321
|
return this.store.register_component(t);
|
|
1072
1322
|
}
|
|
1073
1323
|
register_tag() {
|
|
1074
|
-
return this.store.register_component(
|
|
1324
|
+
return this.store.register_component({});
|
|
1075
1325
|
}
|
|
1076
1326
|
register_event(t) {
|
|
1077
1327
|
return this.store.register_event(t);
|
|
@@ -1079,10 +1329,22 @@ class ot {
|
|
|
1079
1329
|
register_signal() {
|
|
1080
1330
|
return this.store.register_event([]);
|
|
1081
1331
|
}
|
|
1332
|
+
register_resource(t, e) {
|
|
1333
|
+
return this.store.register_resource(
|
|
1334
|
+
t,
|
|
1335
|
+
e
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
resource(t) {
|
|
1339
|
+
return this.store.get_resource_reader(t);
|
|
1340
|
+
}
|
|
1341
|
+
set_resource(t, e) {
|
|
1342
|
+
this.store.get_resource_channel(t).write(e);
|
|
1343
|
+
}
|
|
1082
1344
|
create_entity() {
|
|
1083
1345
|
return this.store.create_entity();
|
|
1084
1346
|
}
|
|
1085
|
-
|
|
1347
|
+
destroy_entity_deferred(t) {
|
|
1086
1348
|
this.store.destroy_entity_deferred(t);
|
|
1087
1349
|
}
|
|
1088
1350
|
is_alive(t) {
|
|
@@ -1092,7 +1354,7 @@ class ot {
|
|
|
1092
1354
|
return this.store.entity_count;
|
|
1093
1355
|
}
|
|
1094
1356
|
add_component(t, e, s) {
|
|
1095
|
-
this.store.add_component(t, e, s ??
|
|
1357
|
+
return this.store.add_component(t, e, s ?? D), this;
|
|
1096
1358
|
}
|
|
1097
1359
|
add_components(t, e) {
|
|
1098
1360
|
this.store.add_components(t, e);
|
|
@@ -1106,9 +1368,23 @@ class ot {
|
|
|
1106
1368
|
has_component(t, e) {
|
|
1107
1369
|
return this.store.has_component(t, e);
|
|
1108
1370
|
}
|
|
1371
|
+
batch_add_component(t, e, s) {
|
|
1372
|
+
this.store.batch_add_component(t, e, s);
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Bulk remove a component from ALL entities in the given archetype.
|
|
1376
|
+
* O(columns) via TypedArray.set() instead of O(N×columns).
|
|
1377
|
+
*/
|
|
1378
|
+
batch_remove_component(t, e) {
|
|
1379
|
+
this.store.batch_remove_component(t, e);
|
|
1380
|
+
}
|
|
1109
1381
|
get_field(t, e, s) {
|
|
1110
|
-
const n = this.store.get_entity_archetype(
|
|
1111
|
-
return n.read_field(r,
|
|
1382
|
+
const n = this.store.get_entity_archetype(t), r = this.store.get_entity_row(t);
|
|
1383
|
+
return n.read_field(r, e, s);
|
|
1384
|
+
}
|
|
1385
|
+
set_field(t, e, s, n) {
|
|
1386
|
+
const r = this.store.get_entity_archetype(t), i = this.store.get_entity_row(t), _ = r.get_column(e, s);
|
|
1387
|
+
_[i] = n;
|
|
1112
1388
|
}
|
|
1113
1389
|
emit(t, e) {
|
|
1114
1390
|
e === void 0 ? this.store.emit_signal(t) : this.store.emit_event(t, e);
|
|
@@ -1122,26 +1398,26 @@ class ot {
|
|
|
1122
1398
|
}
|
|
1123
1399
|
/** QueryResolver implementation — creates or retrieves a cached Query. */
|
|
1124
1400
|
_resolve_query(t, e, s, n) {
|
|
1125
|
-
const r = t.hash(), i = e ? e.hash() : 0, _ = s ? s.hash() : 0,
|
|
1401
|
+
const r = t.hash(), i = e ? e.hash() : 0, _ = s ? s.hash() : 0, c = r ^ Math.imul(i, tt) ^ Math.imul(_, et) | 0, o = this._find_cached(c, t, e, s);
|
|
1126
1402
|
if (o !== void 0) return o.query;
|
|
1127
|
-
const
|
|
1403
|
+
const h = this.store.register_query(
|
|
1128
1404
|
t,
|
|
1129
1405
|
e ?? void 0,
|
|
1130
1406
|
s ?? void 0
|
|
1131
|
-
),
|
|
1132
|
-
|
|
1407
|
+
), a = new Pt(
|
|
1408
|
+
h,
|
|
1133
1409
|
n,
|
|
1134
1410
|
this,
|
|
1135
1411
|
t.copy(),
|
|
1136
1412
|
e?.copy() ?? null,
|
|
1137
1413
|
s?.copy() ?? null
|
|
1138
1414
|
);
|
|
1139
|
-
return
|
|
1415
|
+
return K(this.query_cache, c, {
|
|
1140
1416
|
include_mask: t.copy(),
|
|
1141
1417
|
exclude_mask: e?.copy() ?? null,
|
|
1142
1418
|
any_of_mask: s?.copy() ?? null,
|
|
1143
|
-
query:
|
|
1144
|
-
}),
|
|
1419
|
+
query: a
|
|
1420
|
+
}), a;
|
|
1145
1421
|
}
|
|
1146
1422
|
_find_cached(t, e, s, n) {
|
|
1147
1423
|
const r = this.query_cache.get(t);
|
|
@@ -1152,14 +1428,18 @@ class ot {
|
|
|
1152
1428
|
return _;
|
|
1153
1429
|
}
|
|
1154
1430
|
}
|
|
1431
|
+
// any: overload implementation must unify bare fn, (fn, query_fn), and SystemConfig
|
|
1155
1432
|
register_system(t, e) {
|
|
1156
1433
|
let s;
|
|
1157
|
-
if (typeof t == "function")
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1434
|
+
if (typeof t == "function")
|
|
1435
|
+
if (e !== void 0) {
|
|
1436
|
+
const i = e(new St(this)), _ = this.ctx, c = t;
|
|
1437
|
+
s = { fn: (o, h) => c(i, _, h) };
|
|
1438
|
+
} else
|
|
1439
|
+
s = { fn: t };
|
|
1440
|
+
else
|
|
1161
1441
|
s = t;
|
|
1162
|
-
const n =
|
|
1442
|
+
const n = Dt(this.next_system_id++), r = Object.freeze(
|
|
1163
1443
|
Object.assign({ id: n }, s)
|
|
1164
1444
|
);
|
|
1165
1445
|
return this.systems.add(r), r;
|
|
@@ -1175,17 +1455,17 @@ class ot {
|
|
|
1175
1455
|
}
|
|
1176
1456
|
startup() {
|
|
1177
1457
|
for (const t of this.systems.values())
|
|
1178
|
-
t.on_added?.(this.
|
|
1458
|
+
t.on_added?.(this.ctx);
|
|
1179
1459
|
this.schedule.run_startup(this.ctx);
|
|
1180
1460
|
}
|
|
1181
1461
|
update(t) {
|
|
1182
|
-
if (this.
|
|
1462
|
+
if (this.schedule.has_fixed_systems()) {
|
|
1183
1463
|
this._accumulator += t;
|
|
1184
1464
|
const e = this._max_fixed_steps * this._fixed_timestep;
|
|
1185
1465
|
for (this._accumulator > e && (this._accumulator = e); this._accumulator >= this._fixed_timestep; )
|
|
1186
1466
|
this.schedule.run_fixed_update(this.ctx, this._fixed_timestep), this._accumulator -= this._fixed_timestep;
|
|
1187
1467
|
}
|
|
1188
|
-
this.schedule.run_update(this.ctx, t);
|
|
1468
|
+
this.schedule.run_update(this.ctx, t), this.store.clear_events();
|
|
1189
1469
|
}
|
|
1190
1470
|
flush() {
|
|
1191
1471
|
this.ctx.flush();
|
|
@@ -1197,9 +1477,9 @@ class ot {
|
|
|
1197
1477
|
}
|
|
1198
1478
|
}
|
|
1199
1479
|
export {
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1480
|
+
Nt as ECS,
|
|
1481
|
+
Pt as Query,
|
|
1482
|
+
St as QueryBuilder,
|
|
1483
|
+
Et as SCHEDULE,
|
|
1484
|
+
Ot as SystemContext
|
|
1205
1485
|
};
|