@oasys/oecs 0.1.2 → 0.2.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/README.md +172 -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 +673 -321
- 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 +3 -2
- package/dist/world.d.ts +0 -73
- package/dist/world.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,34 +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
|
-
function
|
|
13
|
-
return
|
|
12
|
+
function N(l, t, e) {
|
|
13
|
+
return l;
|
|
14
14
|
}
|
|
15
|
-
const
|
|
16
|
-
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 {
|
|
17
17
|
_words;
|
|
18
18
|
constructor(t) {
|
|
19
|
-
this._words = t ?? new Array(
|
|
19
|
+
this._words = t ?? new Array(ot).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 >>> k;
|
|
23
|
+
return e >= this._words.length ? !1 : (this._words[e] & 1 << (t & I)) !== 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 >>> k;
|
|
27
|
+
e >= this._words.length && this.grow(e + 1), this._words[e] |= 1 << (t & I);
|
|
28
28
|
}
|
|
29
29
|
clear(t) {
|
|
30
|
-
const e = t >>>
|
|
31
|
-
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)));
|
|
32
32
|
}
|
|
33
33
|
/** True if any bit is set in both this and other (non-empty intersection). */
|
|
34
34
|
overlaps(t) {
|
|
@@ -56,25 +56,25 @@ class v {
|
|
|
56
56
|
return !0;
|
|
57
57
|
}
|
|
58
58
|
copy() {
|
|
59
|
-
return new
|
|
59
|
+
return new x(this._words.slice());
|
|
60
60
|
}
|
|
61
61
|
copy_with_set(t) {
|
|
62
|
-
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);
|
|
63
63
|
for (let i = 0; i < this._words.length; i++) r[i] = this._words[i];
|
|
64
|
-
return r[e] |= 1 << (t &
|
|
64
|
+
return r[e] |= 1 << (t & I), new x(r);
|
|
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 >>> k;
|
|
68
|
+
return s < e.length && (e[s] &= ~(1 << (t & I))), new x(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 = J;
|
|
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, Z);
|
|
78
78
|
return t;
|
|
79
79
|
}
|
|
80
80
|
/** Iterate all set bits via lowest-set-bit extraction. */
|
|
@@ -83,9 +83,9 @@ class v {
|
|
|
83
83
|
for (let s = 0; s < e.length; s++) {
|
|
84
84
|
let n = e[s];
|
|
85
85
|
if (n === 0) continue;
|
|
86
|
-
const r = s <<
|
|
86
|
+
const r = s << k;
|
|
87
87
|
for (; n !== 0; ) {
|
|
88
|
-
const i = n & -n >>> 0, _ =
|
|
88
|
+
const i = n & -n >>> 0, _ = I - Math.clz32(i);
|
|
89
89
|
t(r + _), n ^= i;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -98,14 +98,144 @@ class v {
|
|
|
98
98
|
this._words = s;
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
105
234
|
);
|
|
106
|
-
class
|
|
235
|
+
class wt {
|
|
107
236
|
field_names;
|
|
108
237
|
columns;
|
|
238
|
+
// any: type-erased storage — channel is stored in Map<number, EventChannel>, F is lost
|
|
109
239
|
reader;
|
|
110
240
|
constructor(t) {
|
|
111
241
|
this.field_names = t, this.columns = [];
|
|
@@ -133,44 +263,92 @@ class C {
|
|
|
133
263
|
t[e].length = 0;
|
|
134
264
|
}
|
|
135
265
|
}
|
|
136
|
-
const
|
|
137
|
-
|
|
266
|
+
const vt = (l) => N(
|
|
267
|
+
l
|
|
138
268
|
);
|
|
139
|
-
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 {
|
|
140
307
|
id;
|
|
141
308
|
mask;
|
|
142
309
|
has_columns;
|
|
143
|
-
|
|
310
|
+
_entity_ids;
|
|
144
311
|
length = 0;
|
|
145
312
|
edges = [];
|
|
146
|
-
//
|
|
147
|
-
//
|
|
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.
|
|
148
325
|
column_groups = [];
|
|
149
|
-
// Dense list of ComponentIDs that have columns — used
|
|
150
|
-
// data-bearing components in copy/add/remove operations.
|
|
326
|
+
// Dense list of ComponentIDs that have columns — used for copy_shared_from.
|
|
151
327
|
_column_ids = [];
|
|
152
|
-
constructor(t, e, s) {
|
|
153
|
-
if (this.id = t, this.mask = e, s)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
columns: i,
|
|
164
|
-
record: _
|
|
165
|
-
}, 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);
|
|
166
339
|
}
|
|
340
|
+
}
|
|
167
341
|
this.has_columns = this._column_ids.length > 0;
|
|
168
342
|
}
|
|
169
343
|
get entity_count() {
|
|
170
344
|
return this.length;
|
|
171
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
|
+
}
|
|
172
350
|
get entity_list() {
|
|
173
|
-
return this.
|
|
351
|
+
return this._entity_ids.view();
|
|
174
352
|
}
|
|
175
353
|
has_component(t) {
|
|
176
354
|
return this.mask.has(t);
|
|
@@ -180,36 +358,39 @@ class W {
|
|
|
180
358
|
}
|
|
181
359
|
/** Get a single field's column. Valid data: indices 0..entity_count-1. */
|
|
182
360
|
get_column(t, e) {
|
|
183
|
-
const s =
|
|
184
|
-
return
|
|
185
|
-
}
|
|
186
|
-
/** Get all columns for a component as { fieldName: number[] }. */
|
|
187
|
-
get_column_group(t) {
|
|
188
|
-
const e = this.column_groups[t];
|
|
189
|
-
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;
|
|
190
363
|
}
|
|
191
364
|
write_fields(t, e, s) {
|
|
192
|
-
const n = this.
|
|
193
|
-
if (
|
|
194
|
-
const
|
|
195
|
-
for (let
|
|
196
|
-
|
|
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[_];
|
|
197
378
|
}
|
|
198
379
|
read_field(t, e, s) {
|
|
199
|
-
const n = this.
|
|
200
|
-
if (
|
|
201
|
-
const
|
|
202
|
-
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];
|
|
203
384
|
}
|
|
204
385
|
/** Copy all shared component columns from source archetype at src_row into dst_row. */
|
|
205
386
|
copy_shared_from(t, e, s) {
|
|
206
|
-
const n = t.
|
|
207
|
-
for (let
|
|
208
|
-
const
|
|
209
|
-
if (
|
|
210
|
-
const
|
|
211
|
-
for (let
|
|
212
|
-
|
|
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];
|
|
213
394
|
}
|
|
214
395
|
}
|
|
215
396
|
/**
|
|
@@ -218,49 +399,88 @@ class W {
|
|
|
218
399
|
*/
|
|
219
400
|
add_entity(t) {
|
|
220
401
|
const e = this.length;
|
|
221
|
-
this.
|
|
222
|
-
const s = this.
|
|
223
|
-
for (let n = 0; n < s.length; n++)
|
|
224
|
-
|
|
225
|
-
for (let i = 0; i < r.columns.length; i++)
|
|
226
|
-
r.columns[i].push(0);
|
|
227
|
-
}
|
|
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);
|
|
228
406
|
return this.length++, e;
|
|
229
407
|
}
|
|
230
408
|
/**
|
|
231
409
|
* Remove entity at row via swap-and-pop. Swaps the last entity into the
|
|
232
410
|
* vacated row to keep data dense. Returns the entity_index of the swapped
|
|
233
|
-
* entity (so Store can update its row), or
|
|
411
|
+
* entity (so Store can update its row), or NO_SWAP if no swap was needed.
|
|
234
412
|
*/
|
|
235
413
|
remove_entity(t) {
|
|
236
414
|
const e = this.length - 1;
|
|
237
|
-
let s =
|
|
238
|
-
const n = this.
|
|
415
|
+
let s = y;
|
|
416
|
+
const n = this._flat_columns, r = this._entity_ids.buf;
|
|
239
417
|
if (t !== e) {
|
|
240
|
-
|
|
241
|
-
for (let
|
|
242
|
-
|
|
243
|
-
for (let _ = 0; _ < i.columns.length; _++)
|
|
244
|
-
i.columns[_][t] = i.columns[_][e], i.columns[_].pop();
|
|
245
|
-
}
|
|
418
|
+
r[t] = r[e], s = m(r[t]);
|
|
419
|
+
for (let i = 0; i < n.length; i++)
|
|
420
|
+
n[i].swap_remove(t);
|
|
246
421
|
} else
|
|
247
|
-
for (let
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
i.columns[_].pop();
|
|
251
|
-
}
|
|
252
|
-
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;
|
|
253
425
|
}
|
|
254
426
|
/** Tag-optimized add: skip column push entirely (no data to store). */
|
|
255
427
|
add_entity_tag(t) {
|
|
256
428
|
const e = this.length;
|
|
257
|
-
return this.
|
|
429
|
+
return this._entity_ids.push(t), this.length++, e;
|
|
258
430
|
}
|
|
259
431
|
/** Tag-optimized remove via swap-and-pop: skip column swap/pop entirely. */
|
|
260
432
|
remove_entity_tag(t) {
|
|
261
433
|
const e = this.length - 1;
|
|
262
|
-
let s =
|
|
263
|
-
|
|
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;
|
|
264
484
|
}
|
|
265
485
|
get_edge(t) {
|
|
266
486
|
return this.edges[t];
|
|
@@ -269,12 +489,25 @@ class W {
|
|
|
269
489
|
this.edges[t] = e;
|
|
270
490
|
}
|
|
271
491
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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]);
|
|
275
509
|
}
|
|
276
|
-
|
|
277
|
-
class $ {
|
|
510
|
+
class At {
|
|
278
511
|
// --- Entity ID management ---
|
|
279
512
|
// Generational slot allocator: entity_generations[index] holds the current
|
|
280
513
|
// generation for that slot. Free indices are recycled via a stack.
|
|
@@ -283,7 +516,7 @@ class $ {
|
|
|
283
516
|
entity_free_indices = [];
|
|
284
517
|
entity_alive_count = 0;
|
|
285
518
|
// --- Component metadata ---
|
|
286
|
-
// Parallel array indexed by ComponentID: field_names and
|
|
519
|
+
// Parallel array indexed by ComponentID: field_names, field_index, and field_types
|
|
287
520
|
// for building archetype column layouts.
|
|
288
521
|
component_metas = [];
|
|
289
522
|
component_count = 0;
|
|
@@ -291,6 +524,10 @@ class $ {
|
|
|
291
524
|
// Parallel array indexed by EventID: each channel holds SoA columns + reader.
|
|
292
525
|
event_channels = [];
|
|
293
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;
|
|
294
531
|
// --- Archetype management ---
|
|
295
532
|
archetypes = [];
|
|
296
533
|
// Hash-bucketed lookup: BitSet.hash() → ArchetypeID[] for deduplication
|
|
@@ -316,8 +553,9 @@ class $ {
|
|
|
316
553
|
pending_add_values = [];
|
|
317
554
|
pending_remove_ids = [];
|
|
318
555
|
pending_remove_defs = [];
|
|
319
|
-
|
|
320
|
-
|
|
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());
|
|
321
559
|
}
|
|
322
560
|
// =======================================================
|
|
323
561
|
// Archetype graph
|
|
@@ -332,28 +570,29 @@ class $ {
|
|
|
332
570
|
arch_get_or_create_from_mask(t) {
|
|
333
571
|
const e = t.hash(), s = this.archetype_map.get(e);
|
|
334
572
|
if (s !== void 0) {
|
|
335
|
-
for (let
|
|
336
|
-
if (this.archetypes[s[
|
|
337
|
-
return s[
|
|
573
|
+
for (let c = 0; c < s.length; c++)
|
|
574
|
+
if (this.archetypes[s[c]].mask.equals(t))
|
|
575
|
+
return s[c];
|
|
338
576
|
}
|
|
339
|
-
const n =
|
|
340
|
-
t.for_each((
|
|
341
|
-
const o =
|
|
342
|
-
|
|
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({
|
|
343
581
|
component_id: o,
|
|
344
|
-
field_names:
|
|
345
|
-
field_index:
|
|
582
|
+
field_names: h.field_names,
|
|
583
|
+
field_index: h.field_index,
|
|
584
|
+
field_types: h.field_types
|
|
346
585
|
});
|
|
347
586
|
});
|
|
348
|
-
const i = new
|
|
349
|
-
this.archetypes.push(i),
|
|
350
|
-
const o =
|
|
351
|
-
let
|
|
352
|
-
|
|
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);
|
|
353
592
|
});
|
|
354
593
|
const _ = this.registered_queries;
|
|
355
|
-
for (let
|
|
356
|
-
const o = _[
|
|
594
|
+
for (let c = 0; c < _.length; c++) {
|
|
595
|
+
const o = _[c];
|
|
357
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);
|
|
358
597
|
}
|
|
359
598
|
return n;
|
|
@@ -384,37 +623,44 @@ class $ {
|
|
|
384
623
|
arch_cache_edge(t, e, s) {
|
|
385
624
|
const n = t.get_edge(s) ?? {
|
|
386
625
|
add: null,
|
|
387
|
-
remove: null
|
|
626
|
+
remove: null,
|
|
627
|
+
add_map: null,
|
|
628
|
+
remove_map: null
|
|
388
629
|
};
|
|
389
|
-
n.add = e.id, t.set_edge(s, n);
|
|
390
|
-
const r = e.get_edge(s) ?? {
|
|
391
|
-
|
|
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);
|
|
392
638
|
}
|
|
393
639
|
// =======================================================
|
|
394
640
|
// Entity lifecycle
|
|
395
641
|
// =======================================================
|
|
396
642
|
create_entity() {
|
|
397
643
|
let t, e;
|
|
398
|
-
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] =
|
|
399
|
-
const s =
|
|
400
|
-
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;
|
|
401
647
|
}
|
|
402
648
|
/** Immediately destroy an entity, removing it from its archetype. */
|
|
403
649
|
destroy_entity(t) {
|
|
404
650
|
if (!this.is_alive(t))
|
|
405
651
|
return;
|
|
406
|
-
const e =
|
|
407
|
-
if (s !==
|
|
652
|
+
const e = m(t), s = this.entity_row[e];
|
|
653
|
+
if (s !== v) {
|
|
408
654
|
const i = this.arch_get(this.entity_archetype[e]).remove_entity(s);
|
|
409
|
-
i !==
|
|
655
|
+
i !== y && (this.entity_row[i] = s);
|
|
410
656
|
}
|
|
411
|
-
this.entity_archetype[e] =
|
|
412
|
-
const n =
|
|
413
|
-
this.entity_generations[e] = n + 1 &
|
|
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--;
|
|
414
660
|
}
|
|
415
661
|
is_alive(t) {
|
|
416
|
-
const e =
|
|
417
|
-
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);
|
|
418
664
|
}
|
|
419
665
|
get entity_count() {
|
|
420
666
|
return this.entity_alive_count;
|
|
@@ -431,14 +677,14 @@ class $ {
|
|
|
431
677
|
if (t.length === 0) return;
|
|
432
678
|
const e = this.entity_archetype, s = this.entity_row, n = this.entity_generations, r = this.archetypes, i = this.entity_high_water;
|
|
433
679
|
for (let _ = 0; _ < t.length; _++) {
|
|
434
|
-
const
|
|
435
|
-
if (o >= i || n[o] !==
|
|
436
|
-
const
|
|
437
|
-
if (
|
|
438
|
-
const u = r[e[o]], d = u.has_columns ? u.remove_entity(
|
|
439
|
-
d !==
|
|
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);
|
|
440
686
|
}
|
|
441
|
-
e[o] =
|
|
687
|
+
e[o] = v, s[o] = v, n[o] = h + 1 & X, this.entity_free_indices.push(o), this.entity_alive_count--;
|
|
442
688
|
}
|
|
443
689
|
t.length = 0;
|
|
444
690
|
}
|
|
@@ -446,7 +692,7 @@ class $ {
|
|
|
446
692
|
return this.pending_destroy.length;
|
|
447
693
|
}
|
|
448
694
|
add_component_deferred(t, e, s) {
|
|
449
|
-
this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ??
|
|
695
|
+
this.pending_add_ids.push(t), this.pending_add_defs.push(e), this.pending_add_values.push(s ?? D);
|
|
450
696
|
}
|
|
451
697
|
remove_component_deferred(t, e) {
|
|
452
698
|
this.pending_remove_ids.push(t), this.pending_remove_defs.push(e);
|
|
@@ -456,37 +702,47 @@ class $ {
|
|
|
456
702
|
}
|
|
457
703
|
/** Batch-apply all deferred component additions. */
|
|
458
704
|
_flush_adds() {
|
|
459
|
-
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,
|
|
460
|
-
for (let
|
|
461
|
-
const u = t[
|
|
462
|
-
if (d >=
|
|
463
|
-
const
|
|
464
|
-
if (
|
|
465
|
-
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]);
|
|
466
712
|
continue;
|
|
467
713
|
}
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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;
|
|
475
727
|
}
|
|
476
728
|
t.length = 0, e.length = 0, s.length = 0;
|
|
477
729
|
}
|
|
478
730
|
/** Batch-apply all deferred component removals. */
|
|
479
731
|
_flush_removes() {
|
|
480
|
-
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;
|
|
481
733
|
for (let o = 0; o < s; o++) {
|
|
482
|
-
const
|
|
483
|
-
if (
|
|
484
|
-
const d = n[
|
|
485
|
-
if (!
|
|
486
|
-
const
|
|
487
|
-
w
|
|
488
|
-
|
|
489
|
-
|
|
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];
|
|
490
746
|
}
|
|
491
747
|
t.length = 0, e.length = 0;
|
|
492
748
|
}
|
|
@@ -497,15 +753,15 @@ class $ {
|
|
|
497
753
|
// Component registration
|
|
498
754
|
// =======================================================
|
|
499
755
|
register_component(t) {
|
|
500
|
-
const e =
|
|
501
|
-
for (let
|
|
502
|
-
|
|
503
|
-
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;
|
|
504
760
|
}
|
|
505
761
|
add_component(t, e, s) {
|
|
506
762
|
if (!this.is_alive(t))
|
|
507
763
|
return;
|
|
508
|
-
const n =
|
|
764
|
+
const n = m(t), r = this.entity_archetype[n], i = this.arch_get(r);
|
|
509
765
|
if (i.has_component(e)) {
|
|
510
766
|
i.write_fields(
|
|
511
767
|
this.entity_row[n],
|
|
@@ -517,23 +773,24 @@ class $ {
|
|
|
517
773
|
const _ = this.arch_resolve_add(
|
|
518
774
|
r,
|
|
519
775
|
e
|
|
520
|
-
),
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
|
|
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,
|
|
528
785
|
e,
|
|
529
786
|
s
|
|
530
|
-
), this.entity_archetype[n] = _, this.entity_row[n] =
|
|
787
|
+
), this.entity_archetype[n] = _, this.entity_row[n] = h;
|
|
531
788
|
}
|
|
532
789
|
/** Add multiple components in one transition (resolves final archetype, then moves once). */
|
|
533
790
|
add_components(t, e) {
|
|
534
791
|
if (!this.is_alive(t))
|
|
535
792
|
return;
|
|
536
|
-
const s =
|
|
793
|
+
const s = m(t), n = this.entity_archetype[s];
|
|
537
794
|
let r = n;
|
|
538
795
|
for (let i = 0; i < e.length; i++)
|
|
539
796
|
r = this.arch_resolve_add(
|
|
@@ -541,77 +798,107 @@ class $ {
|
|
|
541
798
|
e[i].def
|
|
542
799
|
);
|
|
543
800
|
if (r !== n) {
|
|
544
|
-
const i = this.arch_get(n), _ = this.arch_get(r),
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const
|
|
548
|
-
c
|
|
549
|
-
}
|
|
550
|
-
|
|
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++)
|
|
551
809
|
_.write_fields(
|
|
552
810
|
o,
|
|
553
|
-
e[
|
|
554
|
-
e[
|
|
811
|
+
e[h].def,
|
|
812
|
+
e[h].values ?? D
|
|
555
813
|
);
|
|
556
814
|
this.entity_archetype[s] = r, this.entity_row[s] = o;
|
|
557
815
|
} else {
|
|
558
816
|
const i = this.arch_get(n), _ = this.entity_row[s];
|
|
559
|
-
for (let
|
|
817
|
+
for (let c = 0; c < e.length; c++)
|
|
560
818
|
i.write_fields(
|
|
561
819
|
_,
|
|
562
|
-
e[
|
|
563
|
-
e[
|
|
820
|
+
e[c].def,
|
|
821
|
+
e[c].values ?? D
|
|
564
822
|
);
|
|
565
823
|
}
|
|
566
824
|
}
|
|
567
825
|
remove_component(t, e) {
|
|
568
826
|
if (!this.is_alive(t))
|
|
569
827
|
return;
|
|
570
|
-
const s =
|
|
828
|
+
const s = m(t), n = this.entity_archetype[s], r = this.arch_get(n);
|
|
571
829
|
if (!r.has_component(e)) return;
|
|
572
830
|
const i = this.arch_resolve_remove(
|
|
573
831
|
n,
|
|
574
832
|
e
|
|
575
|
-
), _ = this.arch_get(i),
|
|
576
|
-
_.
|
|
577
|
-
const c = r.remove_entity(h);
|
|
578
|
-
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];
|
|
579
835
|
}
|
|
580
836
|
/** Remove multiple components in one transition (resolves final archetype, then moves once). */
|
|
581
837
|
remove_components(t, e) {
|
|
582
838
|
if (!this.is_alive(t))
|
|
583
839
|
return;
|
|
584
|
-
const s =
|
|
840
|
+
const s = m(t), n = this.entity_archetype[s];
|
|
585
841
|
let r = n;
|
|
586
|
-
for (let
|
|
842
|
+
for (let h = 0; h < e.length; h++)
|
|
587
843
|
r = this.arch_resolve_remove(
|
|
588
844
|
r,
|
|
589
|
-
e[
|
|
845
|
+
e[h]
|
|
590
846
|
);
|
|
591
847
|
if (r === n) return;
|
|
592
|
-
const i = this.arch_get(n), _ = this.arch_get(r),
|
|
593
|
-
_.
|
|
594
|
-
const c = i.remove_entity(h);
|
|
595
|
-
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];
|
|
596
850
|
}
|
|
597
851
|
has_component(t, e) {
|
|
598
852
|
if (!this.is_alive(t))
|
|
599
853
|
return !1;
|
|
600
|
-
const s =
|
|
854
|
+
const s = m(t);
|
|
601
855
|
return this.arch_get(
|
|
602
856
|
this.entity_archetype[s]
|
|
603
857
|
).has_component(e);
|
|
604
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
|
+
}
|
|
605
892
|
// =======================================================
|
|
606
893
|
// Direct data access (used by SystemContext)
|
|
607
894
|
// =======================================================
|
|
608
895
|
get_entity_archetype(t) {
|
|
609
896
|
return this.arch_get(
|
|
610
|
-
this.entity_archetype[
|
|
897
|
+
this.entity_archetype[m(t)]
|
|
611
898
|
);
|
|
612
899
|
}
|
|
613
900
|
get_entity_row(t) {
|
|
614
|
-
return this.entity_row[
|
|
901
|
+
return this.entity_row[m(t)];
|
|
615
902
|
}
|
|
616
903
|
// =======================================================
|
|
617
904
|
// Query support
|
|
@@ -635,28 +922,28 @@ class $ {
|
|
|
635
922
|
);
|
|
636
923
|
let i, _ = !1;
|
|
637
924
|
for (let o = 0; o < n.length; o++) {
|
|
638
|
-
let
|
|
639
|
-
if (
|
|
640
|
-
const
|
|
641
|
-
for (;
|
|
642
|
-
const u =
|
|
643
|
-
|
|
644
|
-
const
|
|
645
|
-
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) {
|
|
646
933
|
_ = !0;
|
|
647
934
|
break;
|
|
648
935
|
}
|
|
649
|
-
(!i ||
|
|
936
|
+
(!i || g.size < i.size) && (i = g);
|
|
650
937
|
}
|
|
651
938
|
if (_) break;
|
|
652
939
|
}
|
|
653
940
|
if (_ || !i) return [];
|
|
654
|
-
const
|
|
941
|
+
const c = [];
|
|
655
942
|
for (const o of i) {
|
|
656
|
-
const
|
|
657
|
-
|
|
943
|
+
const h = this.arch_get(o);
|
|
944
|
+
h.matches(t) && (!e || !h.mask.overlaps(e)) && (!s || h.mask.overlaps(s)) && c.push(h);
|
|
658
945
|
}
|
|
659
|
-
return
|
|
946
|
+
return c;
|
|
660
947
|
}
|
|
661
948
|
/**
|
|
662
949
|
* Register a live query. Returns a mutable Archetype[] that this Store will
|
|
@@ -682,7 +969,7 @@ class $ {
|
|
|
682
969
|
// Event channels
|
|
683
970
|
// =======================================================
|
|
684
971
|
register_event(t) {
|
|
685
|
-
const e =
|
|
972
|
+
const e = pt(this.event_count++), s = new wt(t);
|
|
686
973
|
return this.event_channels.push(s), e;
|
|
687
974
|
}
|
|
688
975
|
emit_event(t, e) {
|
|
@@ -699,30 +986,43 @@ class $ {
|
|
|
699
986
|
for (let e = 0; e < t.length; e++)
|
|
700
987
|
t[e].clear();
|
|
701
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
|
+
}
|
|
702
1002
|
}
|
|
703
|
-
var
|
|
704
|
-
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 = [
|
|
705
1005
|
"PRE_STARTUP",
|
|
706
1006
|
"STARTUP",
|
|
707
1007
|
"POST_STARTUP"
|
|
708
1008
|
/* POST_STARTUP */
|
|
709
|
-
],
|
|
1009
|
+
], G = [
|
|
710
1010
|
"PRE_UPDATE",
|
|
711
1011
|
"UPDATE",
|
|
712
1012
|
"POST_UPDATE"
|
|
713
1013
|
/* POST_UPDATE */
|
|
714
1014
|
];
|
|
715
|
-
class
|
|
1015
|
+
class kt {
|
|
716
1016
|
label_systems = /* @__PURE__ */ new Map();
|
|
717
1017
|
sorted_cache = /* @__PURE__ */ new Map();
|
|
718
1018
|
system_index = /* @__PURE__ */ new Map();
|
|
719
1019
|
next_insertion_order = 0;
|
|
720
1020
|
constructor() {
|
|
721
|
-
for (let t = 0; t <
|
|
722
|
-
this.label_systems.set(
|
|
1021
|
+
for (let t = 0; t < q.length; t++)
|
|
1022
|
+
this.label_systems.set(q[t], []);
|
|
723
1023
|
this.label_systems.set("FIXED_UPDATE", []);
|
|
724
|
-
for (let t = 0; t <
|
|
725
|
-
this.label_systems.set(
|
|
1024
|
+
for (let t = 0; t < G.length; t++)
|
|
1025
|
+
this.label_systems.set(G[t], []);
|
|
726
1026
|
}
|
|
727
1027
|
add_systems(t, ...e) {
|
|
728
1028
|
for (const s of e) {
|
|
@@ -748,11 +1048,11 @@ class Q {
|
|
|
748
1048
|
this.system_index.delete(t), this.sorted_cache.delete(e);
|
|
749
1049
|
}
|
|
750
1050
|
run_startup(t) {
|
|
751
|
-
for (const e of
|
|
752
|
-
this.run_label(e, t,
|
|
1051
|
+
for (const e of q)
|
|
1052
|
+
this.run_label(e, t, it);
|
|
753
1053
|
}
|
|
754
1054
|
run_update(t, e) {
|
|
755
|
-
for (const s of
|
|
1055
|
+
for (const s of G)
|
|
756
1056
|
this.run_label(s, t, e);
|
|
757
1057
|
}
|
|
758
1058
|
run_fixed_update(t, e) {
|
|
@@ -801,51 +1101,72 @@ class Q {
|
|
|
801
1101
|
for (const o of t)
|
|
802
1102
|
s.set(o.descriptor, /* @__PURE__ */ new Set()), n.set(o.descriptor, 0), r.set(o.descriptor, o.insertion_order), i.add(o.descriptor);
|
|
803
1103
|
for (const o of t) {
|
|
804
|
-
for (const
|
|
805
|
-
i.has(
|
|
806
|
-
for (const
|
|
807
|
-
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));
|
|
808
1108
|
}
|
|
809
1109
|
let _ = [];
|
|
810
1110
|
for (const o of t)
|
|
811
1111
|
n.get(o.descriptor) === 0 && _.push(o.descriptor);
|
|
812
|
-
_.sort((o,
|
|
813
|
-
const
|
|
1112
|
+
_.sort((o, h) => r.get(h) - r.get(o));
|
|
1113
|
+
const c = [];
|
|
814
1114
|
for (; _.length > 0; ) {
|
|
815
1115
|
const o = _.pop();
|
|
816
|
-
|
|
817
|
-
for (const
|
|
818
|
-
const
|
|
819
|
-
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);
|
|
820
1120
|
}
|
|
821
|
-
_.sort((
|
|
1121
|
+
_.sort((h, a) => r.get(a) - r.get(h));
|
|
822
1122
|
}
|
|
823
|
-
if (
|
|
824
|
-
const o = new Set(
|
|
825
|
-
throw new
|
|
826
|
-
|
|
827
|
-
`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(", ")}]`
|
|
828
1128
|
);
|
|
829
1129
|
}
|
|
830
|
-
return
|
|
1130
|
+
return c;
|
|
831
1131
|
}
|
|
832
1132
|
}
|
|
833
|
-
const
|
|
834
|
-
|
|
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 {
|
|
835
1159
|
_archetypes;
|
|
836
1160
|
_defs;
|
|
837
1161
|
_resolver;
|
|
838
1162
|
_include;
|
|
839
1163
|
_exclude;
|
|
840
1164
|
_any_of;
|
|
841
|
-
// Pre-allocated args buffer for each() — avoids allocating a new array per
|
|
842
|
-
// archetype. Holds [columnGroup0, columnGroup1, ..., entityCount].
|
|
843
|
-
_args_buf;
|
|
844
1165
|
constructor(t, e, s, n, r, i) {
|
|
845
|
-
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;
|
|
846
1167
|
}
|
|
847
1168
|
/** Number of matching archetypes (including empty ones). */
|
|
848
|
-
get
|
|
1169
|
+
get archetype_count() {
|
|
849
1170
|
return this._archetypes.length;
|
|
850
1171
|
}
|
|
851
1172
|
/** Total entity count across all matching archetypes. */
|
|
@@ -864,22 +1185,6 @@ class J {
|
|
|
864
1185
|
for (let e = 0; e < t.length; e++)
|
|
865
1186
|
t[e].entity_count > 0 && (yield t[e]);
|
|
866
1187
|
}
|
|
867
|
-
/**
|
|
868
|
-
* Typed per-archetype iteration. Calls fn once per non-empty archetype
|
|
869
|
-
* with column groups for each queried component, plus the entity count.
|
|
870
|
-
* The system is responsible for the inner loop over entities.
|
|
871
|
-
*/
|
|
872
|
-
each(t) {
|
|
873
|
-
const e = this._archetypes, s = this._defs, n = this._args_buf;
|
|
874
|
-
for (let r = 0; r < e.length; r++) {
|
|
875
|
-
const i = e[r], _ = i.entity_count;
|
|
876
|
-
if (_ !== 0) {
|
|
877
|
-
for (let h = 0; h < s.length; h++)
|
|
878
|
-
n[h] = i.get_column_group(s[h]);
|
|
879
|
-
n[s.length] = _, t.apply(null, n);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
1188
|
/** Extend required component set. Returns a new (cached) Query. */
|
|
884
1189
|
and(...t) {
|
|
885
1190
|
const e = this._include.copy(), s = this._defs.slice();
|
|
@@ -894,7 +1199,7 @@ class J {
|
|
|
894
1199
|
}
|
|
895
1200
|
/** Exclude archetypes that have any of these components. */
|
|
896
1201
|
not(...t) {
|
|
897
|
-
const e = this._exclude ? this._exclude.copy() : new
|
|
1202
|
+
const e = this._exclude ? this._exclude.copy() : new x();
|
|
898
1203
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
899
1204
|
return this._resolver._resolve_query(
|
|
900
1205
|
this._include,
|
|
@@ -904,8 +1209,8 @@ class J {
|
|
|
904
1209
|
);
|
|
905
1210
|
}
|
|
906
1211
|
/** Require at least one of these components. */
|
|
907
|
-
|
|
908
|
-
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();
|
|
909
1214
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
910
1215
|
return this._resolver._resolve_query(
|
|
911
1216
|
this._include,
|
|
@@ -915,17 +1220,17 @@ class J {
|
|
|
915
1220
|
);
|
|
916
1221
|
}
|
|
917
1222
|
}
|
|
918
|
-
class
|
|
1223
|
+
class St {
|
|
919
1224
|
constructor(t) {
|
|
920
1225
|
this._resolver = t;
|
|
921
1226
|
}
|
|
922
1227
|
every(...t) {
|
|
923
|
-
const e = new
|
|
1228
|
+
const e = new x();
|
|
924
1229
|
for (let s = 0; s < t.length; s++) e.set(t[s]);
|
|
925
1230
|
return this._resolver._resolve_query(e, null, null, t);
|
|
926
1231
|
}
|
|
927
1232
|
}
|
|
928
|
-
class
|
|
1233
|
+
class Ot {
|
|
929
1234
|
store;
|
|
930
1235
|
constructor(t) {
|
|
931
1236
|
this.store = t;
|
|
@@ -934,22 +1239,24 @@ class H {
|
|
|
934
1239
|
return this.store.create_entity();
|
|
935
1240
|
}
|
|
936
1241
|
get_field(t, e, s) {
|
|
937
|
-
const n = this.store.get_entity_archetype(
|
|
938
|
-
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);
|
|
939
1244
|
}
|
|
940
1245
|
set_field(t, e, s, n) {
|
|
941
|
-
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);
|
|
942
1247
|
_[i] = n;
|
|
943
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
|
+
}
|
|
944
1254
|
/** Buffer an entity for deferred destruction (applied at phase flush). */
|
|
945
1255
|
destroy_entity(t) {
|
|
946
1256
|
return this.store.destroy_entity_deferred(t), this;
|
|
947
1257
|
}
|
|
948
|
-
flush_destroyed() {
|
|
949
|
-
this.store.flush_destroyed();
|
|
950
|
-
}
|
|
951
1258
|
add_component(t, e, s) {
|
|
952
|
-
return this.store.add_component_deferred(t, e, s ??
|
|
1259
|
+
return this.store.add_component_deferred(t, e, s ?? D), this;
|
|
953
1260
|
}
|
|
954
1261
|
remove_component(t, e) {
|
|
955
1262
|
return this.store.remove_component_deferred(t, e), this;
|
|
@@ -964,11 +1271,20 @@ class H {
|
|
|
964
1271
|
read(t) {
|
|
965
1272
|
return this.store.get_event_reader(t);
|
|
966
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
|
+
}
|
|
967
1283
|
}
|
|
968
|
-
const
|
|
969
|
-
|
|
970
|
-
)
|
|
971
|
-
class
|
|
1284
|
+
const Dt = (l) => N(
|
|
1285
|
+
l
|
|
1286
|
+
);
|
|
1287
|
+
class Nt {
|
|
972
1288
|
store;
|
|
973
1289
|
schedule;
|
|
974
1290
|
ctx;
|
|
@@ -982,9 +1298,9 @@ class st {
|
|
|
982
1298
|
// Multiple queries can share the same hash (collision), so each bucket is an array.
|
|
983
1299
|
query_cache = /* @__PURE__ */ new Map();
|
|
984
1300
|
// Reusable BitSet for building query masks — avoids allocation per query() call
|
|
985
|
-
scratch_mask = new
|
|
1301
|
+
scratch_mask = new x();
|
|
986
1302
|
constructor(t) {
|
|
987
|
-
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;
|
|
988
1304
|
}
|
|
989
1305
|
get fixed_timestep() {
|
|
990
1306
|
return this._fixed_timestep;
|
|
@@ -995,11 +1311,17 @@ class st {
|
|
|
995
1311
|
get fixed_alpha() {
|
|
996
1312
|
return this._accumulator / this._fixed_timestep;
|
|
997
1313
|
}
|
|
998
|
-
|
|
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
|
+
}
|
|
999
1321
|
return this.store.register_component(t);
|
|
1000
1322
|
}
|
|
1001
1323
|
register_tag() {
|
|
1002
|
-
return this.store.register_component(
|
|
1324
|
+
return this.store.register_component({});
|
|
1003
1325
|
}
|
|
1004
1326
|
register_event(t) {
|
|
1005
1327
|
return this.store.register_event(t);
|
|
@@ -1007,10 +1329,22 @@ class st {
|
|
|
1007
1329
|
register_signal() {
|
|
1008
1330
|
return this.store.register_event([]);
|
|
1009
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
|
+
}
|
|
1010
1344
|
create_entity() {
|
|
1011
1345
|
return this.store.create_entity();
|
|
1012
1346
|
}
|
|
1013
|
-
|
|
1347
|
+
destroy_entity_deferred(t) {
|
|
1014
1348
|
this.store.destroy_entity_deferred(t);
|
|
1015
1349
|
}
|
|
1016
1350
|
is_alive(t) {
|
|
@@ -1020,7 +1354,7 @@ class st {
|
|
|
1020
1354
|
return this.store.entity_count;
|
|
1021
1355
|
}
|
|
1022
1356
|
add_component(t, e, s) {
|
|
1023
|
-
this.store.add_component(t, e, s ??
|
|
1357
|
+
return this.store.add_component(t, e, s ?? D), this;
|
|
1024
1358
|
}
|
|
1025
1359
|
add_components(t, e) {
|
|
1026
1360
|
this.store.add_components(t, e);
|
|
@@ -1034,9 +1368,23 @@ class st {
|
|
|
1034
1368
|
has_component(t, e) {
|
|
1035
1369
|
return this.store.has_component(t, e);
|
|
1036
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
|
+
}
|
|
1037
1381
|
get_field(t, e, s) {
|
|
1038
|
-
const n = this.store.get_entity_archetype(
|
|
1039
|
-
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;
|
|
1040
1388
|
}
|
|
1041
1389
|
emit(t, e) {
|
|
1042
1390
|
e === void 0 ? this.store.emit_signal(t) : this.store.emit_event(t, e);
|
|
@@ -1050,26 +1398,26 @@ class st {
|
|
|
1050
1398
|
}
|
|
1051
1399
|
/** QueryResolver implementation — creates or retrieves a cached Query. */
|
|
1052
1400
|
_resolve_query(t, e, s, n) {
|
|
1053
|
-
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);
|
|
1054
1402
|
if (o !== void 0) return o.query;
|
|
1055
|
-
const
|
|
1403
|
+
const h = this.store.register_query(
|
|
1056
1404
|
t,
|
|
1057
1405
|
e ?? void 0,
|
|
1058
1406
|
s ?? void 0
|
|
1059
|
-
),
|
|
1060
|
-
|
|
1407
|
+
), a = new Pt(
|
|
1408
|
+
h,
|
|
1061
1409
|
n,
|
|
1062
1410
|
this,
|
|
1063
1411
|
t.copy(),
|
|
1064
1412
|
e?.copy() ?? null,
|
|
1065
1413
|
s?.copy() ?? null
|
|
1066
1414
|
);
|
|
1067
|
-
return
|
|
1415
|
+
return K(this.query_cache, c, {
|
|
1068
1416
|
include_mask: t.copy(),
|
|
1069
1417
|
exclude_mask: e?.copy() ?? null,
|
|
1070
1418
|
any_of_mask: s?.copy() ?? null,
|
|
1071
|
-
query:
|
|
1072
|
-
}),
|
|
1419
|
+
query: a
|
|
1420
|
+
}), a;
|
|
1073
1421
|
}
|
|
1074
1422
|
_find_cached(t, e, s, n) {
|
|
1075
1423
|
const r = this.query_cache.get(t);
|
|
@@ -1080,14 +1428,18 @@ class st {
|
|
|
1080
1428
|
return _;
|
|
1081
1429
|
}
|
|
1082
1430
|
}
|
|
1431
|
+
// any: overload implementation must unify bare fn, (fn, query_fn), and SystemConfig
|
|
1083
1432
|
register_system(t, e) {
|
|
1084
1433
|
let s;
|
|
1085
|
-
if (typeof t == "function")
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
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
|
|
1089
1441
|
s = t;
|
|
1090
|
-
const n =
|
|
1442
|
+
const n = Dt(this.next_system_id++), r = Object.freeze(
|
|
1091
1443
|
Object.assign({ id: n }, s)
|
|
1092
1444
|
);
|
|
1093
1445
|
return this.systems.add(r), r;
|
|
@@ -1103,17 +1455,17 @@ class st {
|
|
|
1103
1455
|
}
|
|
1104
1456
|
startup() {
|
|
1105
1457
|
for (const t of this.systems.values())
|
|
1106
|
-
t.on_added?.(this.
|
|
1458
|
+
t.on_added?.(this.ctx);
|
|
1107
1459
|
this.schedule.run_startup(this.ctx);
|
|
1108
1460
|
}
|
|
1109
1461
|
update(t) {
|
|
1110
|
-
if (this.
|
|
1462
|
+
if (this.schedule.has_fixed_systems()) {
|
|
1111
1463
|
this._accumulator += t;
|
|
1112
1464
|
const e = this._max_fixed_steps * this._fixed_timestep;
|
|
1113
1465
|
for (this._accumulator > e && (this._accumulator = e); this._accumulator >= this._fixed_timestep; )
|
|
1114
1466
|
this.schedule.run_fixed_update(this.ctx, this._fixed_timestep), this._accumulator -= this._fixed_timestep;
|
|
1115
1467
|
}
|
|
1116
|
-
this.schedule.run_update(this.ctx, t);
|
|
1468
|
+
this.schedule.run_update(this.ctx, t), this.store.clear_events();
|
|
1117
1469
|
}
|
|
1118
1470
|
flush() {
|
|
1119
1471
|
this.ctx.flush();
|
|
@@ -1125,9 +1477,9 @@ class st {
|
|
|
1125
1477
|
}
|
|
1126
1478
|
}
|
|
1127
1479
|
export {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1480
|
+
Nt as ECS,
|
|
1481
|
+
Pt as Query,
|
|
1482
|
+
St as QueryBuilder,
|
|
1483
|
+
Et as SCHEDULE,
|
|
1484
|
+
Ot as SystemContext
|
|
1133
1485
|
};
|