@idleflowgames/anotherecs 0.1.2 → 0.1.4
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/CHANGELOG.md +14 -0
- package/dist/index.js +113 -49
- package/dist/index.js.map +1 -1
- package/dist/spatial-hash.d.ts +12 -2
- package/package.json +14 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.4
|
|
4
|
+
|
|
5
|
+
- `SpatialHash`: `clear()` is now O(1). Buckets carry a frame stamp and a live
|
|
6
|
+
prefix count, so a stamp bump retires the whole grid and a periodic sweep
|
|
7
|
+
reclaims dead buckets. Queries additionally clamp their cell span to an
|
|
8
|
+
occupied bounding box and a per-column occupied row range, both supersets of
|
|
9
|
+
the true occupied set, so they only ever skip cells that are provably empty.
|
|
10
|
+
Szudzik pairing is inlined at its three call sites with its cx-only half
|
|
11
|
+
hoisted out of the inner loop.
|
|
12
|
+
Result arrays are unchanged in membership AND in order, so a consumer that
|
|
13
|
+
relies on iteration order for determinism is unaffected.
|
|
14
|
+
A whole broadphase frame is 2.32x faster at 50 bodies, 1.90x at 250 and 1.13x
|
|
15
|
+
at 1000; a 253k-op trace recorded from a real game run replays 48% faster.
|
|
16
|
+
|
|
3
17
|
## 0.1.2
|
|
4
18
|
|
|
5
19
|
- No source changes. Toolchain/deps only: Node 24, pnpm 11.5.0, lock-file
|
package/dist/index.js
CHANGED
|
@@ -411,7 +411,7 @@ var d = class {
|
|
|
411
411
|
let n = e.entities;
|
|
412
412
|
if (n.length === 0) return;
|
|
413
413
|
let r = e.stores;
|
|
414
|
-
if (e.yieldPlan.length === e.ids.length && e.ids.length <=
|
|
414
|
+
if (e.yieldPlan.length === e.ids.length && e.ids.length <= 6) {
|
|
415
415
|
switch (e.ids.length) {
|
|
416
416
|
case 1: {
|
|
417
417
|
let e = r[0];
|
|
@@ -445,6 +445,22 @@ var d = class {
|
|
|
445
445
|
}
|
|
446
446
|
break;
|
|
447
447
|
}
|
|
448
|
+
case 5: {
|
|
449
|
+
let e = r[0], i = r[1], a = r[2], o = r[3], s = r[4];
|
|
450
|
+
for (let r = 0; r < n.length; r++) {
|
|
451
|
+
let c = n[r];
|
|
452
|
+
t(c, e.getUnsafe(c), i.getUnsafe(c), a.getUnsafe(c), o.getUnsafe(c), s.getUnsafe(c));
|
|
453
|
+
}
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
case 6: {
|
|
457
|
+
let e = r[0], i = r[1], a = r[2], o = r[3], s = r[4], c = r[5];
|
|
458
|
+
for (let r = 0; r < n.length; r++) {
|
|
459
|
+
let l = n[r];
|
|
460
|
+
t(l, e.getUnsafe(l), i.getUnsafe(l), a.getUnsafe(l), o.getUnsafe(l), s.getUnsafe(l), c.getUnsafe(l));
|
|
461
|
+
}
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
448
464
|
}
|
|
449
465
|
return;
|
|
450
466
|
}
|
|
@@ -1202,11 +1218,18 @@ var T = 65536, E = -1, D = class {
|
|
|
1202
1218
|
for (let e = 0; e < this.count; e++) this.sparse[this.entities[e]] = E;
|
|
1203
1219
|
this.entities.length = 0, this.data.length = 0, this.count = 0, this.freeList.length = 0, this._added.length = 0, this._removed.length = 0, this._changed.length = 0, this._addedFired = 0, this._removedFired = 0, this._version++;
|
|
1204
1220
|
}
|
|
1205
|
-
}, O = class {
|
|
1221
|
+
}, O = 256, k = O - 1, A = 64, j = -2147483648, M = 2147483647, N = class {
|
|
1206
1222
|
invCellSize;
|
|
1207
1223
|
cells = /* @__PURE__ */ new Map();
|
|
1208
1224
|
generation = 0;
|
|
1209
1225
|
seen;
|
|
1226
|
+
occMinCX = 0;
|
|
1227
|
+
occMaxCX = -1;
|
|
1228
|
+
occMinCY = 0;
|
|
1229
|
+
occMaxCY = -1;
|
|
1230
|
+
col = new Int32Array(O * 3);
|
|
1231
|
+
frameGen = 1;
|
|
1232
|
+
sweepIn = A;
|
|
1210
1233
|
constructor(e = 64, t = T) {
|
|
1211
1234
|
if (!(e > 0)) throw Error(`SpatialHash: cellSize must be > 0 (got ${e})`);
|
|
1212
1235
|
this.invCellSize = 1 / e, this.seen = new Int32Array(t);
|
|
@@ -1215,85 +1238,126 @@ var T = 65536, E = -1, D = class {
|
|
|
1215
1238
|
return this.generation = this.generation + 1 | 0, this.generation === 0 && (this.generation = 1), this.generation;
|
|
1216
1239
|
}
|
|
1217
1240
|
clear() {
|
|
1218
|
-
this.
|
|
1241
|
+
this.occMinCX = 0, this.occMaxCX = -1, this.occMinCY = 0, this.occMaxCY = -1;
|
|
1242
|
+
let e = this.frameGen + 1;
|
|
1243
|
+
if (e >= M) {
|
|
1244
|
+
this.cells.clear(), this.col.fill(0), this.frameGen = 1, this.sweepIn = A;
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
this.frameGen = e, --this.sweepIn <= 0 && (this.sweepIn = A, this.cells.forEach(this.pruneStale, this));
|
|
1248
|
+
}
|
|
1249
|
+
pruneStale(e, t) {
|
|
1250
|
+
this.frameGen - e.g >= A && this.cells.delete(t);
|
|
1219
1251
|
}
|
|
1220
1252
|
insert(e, t, n, r) {
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1253
|
+
let i = this.seen;
|
|
1254
|
+
if (e >= i.length) throw Error(`SpatialHash.insert(): entity id ${e} exceeds maxEntities (${i.length}). Construct the SpatialHash with a maxEntities that matches the consuming World's capacity.`);
|
|
1255
|
+
let a = this.cells, o = this.invCellSize, s = Math.floor((t - r) * o), c = Math.floor((t + r) * o), l = Math.floor((n - r) * o), u = Math.floor((n + r) * o);
|
|
1256
|
+
this.occMaxCX < this.occMinCX ? (this.occMinCX = s, this.occMaxCX = c, this.occMinCY = l, this.occMaxCY = u) : (s < this.occMinCX && (this.occMinCX = s), c > this.occMaxCX && (this.occMaxCX = c), l < this.occMinCY && (this.occMinCY = l), u > this.occMaxCY && (this.occMaxCY = u));
|
|
1257
|
+
let d = this.col, f = this.frameGen, p = l < j ? j : l, m = u > M ? M : u;
|
|
1258
|
+
for (let t = s; t <= c; t++) {
|
|
1259
|
+
let n = (t & k) * 3;
|
|
1260
|
+
d[n] === f ? (p < d[n + 1] && (d[n + 1] = p), m > d[n + 2] && (d[n + 2] = m)) : (d[n] = f, d[n + 1] = p, d[n + 2] = m);
|
|
1261
|
+
let r = t >= 0 ? 2 * t : -2 * t - 1, i = r * r + r;
|
|
1262
|
+
for (let t = l; t <= u; t++) {
|
|
1263
|
+
let n = t >= 0 ? 2 * t : -2 * t - 1, o = r >= n ? i + n : n * n + r, s = a.get(o);
|
|
1264
|
+
s === void 0 ? (s = {
|
|
1265
|
+
e: [],
|
|
1266
|
+
n: 0,
|
|
1267
|
+
g: f
|
|
1268
|
+
}, a.set(o, s)) : s.g !== f && (s.g = f, s.n = 0);
|
|
1269
|
+
let c = s.n, l = s.e;
|
|
1270
|
+
c < l.length ? l[c] = e : l.push(e), s.n = c + 1;
|
|
1271
|
+
}
|
|
1226
1272
|
}
|
|
1227
1273
|
}
|
|
1228
1274
|
query(e, t, n, r) {
|
|
1229
1275
|
r.length = 0;
|
|
1230
|
-
let i = this.nextGen(), a = Math.floor((e - n) *
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1276
|
+
let i = this.nextGen(), a = this.cells, o = this.seen, s = this.invCellSize, c = Math.floor((e - n) * s), l = Math.floor((e + n) * s), u = Math.floor((t - n) * s), d = Math.floor((t + n) * s);
|
|
1277
|
+
c < this.occMinCX && (c = this.occMinCX), l > this.occMaxCX && (l = this.occMaxCX), u < this.occMinCY && (u = this.occMinCY), d > this.occMaxCY && (d = this.occMaxCY);
|
|
1278
|
+
let f = this.col, p = this.frameGen;
|
|
1279
|
+
for (let e = c; e <= l; e++) {
|
|
1280
|
+
let t = (e & k) * 3;
|
|
1281
|
+
if (f[t] !== p) continue;
|
|
1282
|
+
let n = u, s = d;
|
|
1283
|
+
n < f[t + 1] && (n = f[t + 1]), s > f[t + 2] && (s = f[t + 2]);
|
|
1284
|
+
let c = e >= 0 ? 2 * e : -2 * e - 1, l = c * c + c;
|
|
1285
|
+
for (let e = n; e <= s; e++) {
|
|
1286
|
+
let t = e >= 0 ? 2 * e : -2 * e - 1, n = a.get(c >= t ? l + t : t * t + c);
|
|
1287
|
+
if (n === void 0 || n.g !== p) continue;
|
|
1288
|
+
let s = n.e;
|
|
1289
|
+
for (let e = 0, t = n.n; e < t; e++) {
|
|
1290
|
+
let t = s[e];
|
|
1291
|
+
o[t] !== i && (o[t] = i, r.push(t));
|
|
1292
|
+
}
|
|
1236
1293
|
}
|
|
1237
1294
|
}
|
|
1238
1295
|
}
|
|
1239
1296
|
queryRadius(e, t, n, r, i, a) {
|
|
1240
1297
|
a.length = 0;
|
|
1241
|
-
let o = this.nextGen(), s = Math.floor((e - n) *
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1298
|
+
let o = this.nextGen(), s = this.cells, c = this.seen, l = this.invCellSize, u = Math.floor((e - n) * l), d = Math.floor((e + n) * l), f = Math.floor((t - n) * l), p = Math.floor((t + n) * l);
|
|
1299
|
+
u < this.occMinCX && (u = this.occMinCX), d > this.occMaxCX && (d = this.occMaxCX), f < this.occMinCY && (f = this.occMinCY), p > this.occMaxCY && (p = this.occMaxCY);
|
|
1300
|
+
let m = this.col, h = this.frameGen;
|
|
1301
|
+
for (let l = u; l <= d; l++) {
|
|
1302
|
+
let u = (l & k) * 3;
|
|
1303
|
+
if (m[u] !== h) continue;
|
|
1304
|
+
let d = f, g = p;
|
|
1305
|
+
d < m[u + 1] && (d = m[u + 1]), g > m[u + 2] && (g = m[u + 2]);
|
|
1306
|
+
let _ = l >= 0 ? 2 * l : -2 * l - 1, v = _ * _ + _;
|
|
1307
|
+
for (let l = d; l <= g; l++) {
|
|
1308
|
+
let u = l >= 0 ? 2 * l : -2 * l - 1, d = s.get(_ >= u ? v + u : u * u + _);
|
|
1309
|
+
if (d === void 0 || d.g !== h) continue;
|
|
1310
|
+
let f = d.e;
|
|
1311
|
+
for (let s = 0, l = d.n; s < l; s++) {
|
|
1312
|
+
let l = f[s];
|
|
1313
|
+
if (c[l] === o) continue;
|
|
1314
|
+
c[l] = o;
|
|
1315
|
+
let u = r(l);
|
|
1316
|
+
if (!u) continue;
|
|
1317
|
+
let d = i(l), p = u.x - e, m = u.y - t, h = p * p + m * m, g = n + d;
|
|
1318
|
+
h <= g * g && a.push(l);
|
|
1319
|
+
}
|
|
1252
1320
|
}
|
|
1253
1321
|
}
|
|
1254
1322
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
return n >= r ? n * n + n + r : r * r + n;
|
|
1258
|
-
}
|
|
1259
|
-
}, k = 0, A = 0, j = 0, M = 0, N = 0, P = !0;
|
|
1260
|
-
function F(e, t, n) {
|
|
1323
|
+
}, P = 0, F = 0, I = 0, L = 0, R = 0, z = !0;
|
|
1324
|
+
function B(e, t, n) {
|
|
1261
1325
|
return {
|
|
1262
|
-
id:
|
|
1326
|
+
id: F++,
|
|
1263
1327
|
name: e,
|
|
1264
1328
|
create: t,
|
|
1265
1329
|
reset: n
|
|
1266
1330
|
};
|
|
1267
1331
|
}
|
|
1268
|
-
function
|
|
1332
|
+
function V(e) {
|
|
1269
1333
|
return {
|
|
1270
|
-
id:
|
|
1334
|
+
id: F++,
|
|
1271
1335
|
name: e,
|
|
1272
1336
|
tag: !0
|
|
1273
1337
|
};
|
|
1274
1338
|
}
|
|
1275
|
-
function
|
|
1339
|
+
function H(e) {
|
|
1276
1340
|
return {
|
|
1277
|
-
id:
|
|
1341
|
+
id: I++,
|
|
1278
1342
|
name: e
|
|
1279
1343
|
};
|
|
1280
1344
|
}
|
|
1281
|
-
function
|
|
1345
|
+
function U(e) {
|
|
1282
1346
|
return {
|
|
1283
|
-
id:
|
|
1347
|
+
id: L++,
|
|
1284
1348
|
name: e
|
|
1285
1349
|
};
|
|
1286
1350
|
}
|
|
1287
|
-
function
|
|
1351
|
+
function W(e, t) {
|
|
1288
1352
|
return {
|
|
1289
|
-
id:
|
|
1353
|
+
id: R++,
|
|
1290
1354
|
name: e,
|
|
1291
1355
|
init: t
|
|
1292
1356
|
};
|
|
1293
1357
|
}
|
|
1294
1358
|
//#endregion
|
|
1295
1359
|
//#region src/world.ts
|
|
1296
|
-
var
|
|
1360
|
+
var G = class {
|
|
1297
1361
|
nextId = 1;
|
|
1298
1362
|
maxEntities;
|
|
1299
1363
|
alive = /* @__PURE__ */ new Set();
|
|
@@ -1505,13 +1569,13 @@ var B = class {
|
|
|
1505
1569
|
t.isTracking() || (t.enableTracking(), this.trackedStores.push(t));
|
|
1506
1570
|
}
|
|
1507
1571
|
added(e) {
|
|
1508
|
-
return this.stores[e.id]?.iterAdded() ??
|
|
1572
|
+
return this.stores[e.id]?.iterAdded() ?? q;
|
|
1509
1573
|
}
|
|
1510
1574
|
removed(e) {
|
|
1511
|
-
return this.stores[e.id]?.iterRemoved() ??
|
|
1575
|
+
return this.stores[e.id]?.iterRemoved() ?? q;
|
|
1512
1576
|
}
|
|
1513
1577
|
changed(e) {
|
|
1514
|
-
return this.stores[e.id]?.iterChanged() ??
|
|
1578
|
+
return this.stores[e.id]?.iterChanged() ?? q;
|
|
1515
1579
|
}
|
|
1516
1580
|
markChanged(e, t) {
|
|
1517
1581
|
this.stores[t.id]?.markChanged(e);
|
|
@@ -1627,9 +1691,9 @@ var B = class {
|
|
|
1627
1691
|
return this.backrefsEnabled;
|
|
1628
1692
|
}
|
|
1629
1693
|
backrefs(e) {
|
|
1630
|
-
if (!this.backrefsEnabled || this.backrefEdges === null) return
|
|
1694
|
+
if (!this.backrefsEnabled || this.backrefEdges === null) return K;
|
|
1631
1695
|
let t = this.backrefEdges.get(e);
|
|
1632
|
-
if (t === void 0 || t.length === 0) return
|
|
1696
|
+
if (t === void 0 || t.length === 0) return K;
|
|
1633
1697
|
let n = !0;
|
|
1634
1698
|
for (let e = 0; e < t.length; e++) if (!this.alive.has(t[e])) {
|
|
1635
1699
|
n = !1;
|
|
@@ -1638,7 +1702,7 @@ var B = class {
|
|
|
1638
1702
|
if (n) return t;
|
|
1639
1703
|
let r = [];
|
|
1640
1704
|
for (let e = 0; e < t.length; e++) this.alive.has(t[e]) && r.push(t[e]);
|
|
1641
|
-
return r.length === 0 ?
|
|
1705
|
+
return r.length === 0 ? K : r;
|
|
1642
1706
|
}
|
|
1643
1707
|
unref(e, t) {
|
|
1644
1708
|
if (!this.backrefsEnabled || this.backrefEdges === null) return;
|
|
@@ -1649,8 +1713,8 @@ var B = class {
|
|
|
1649
1713
|
let a = this.holderToTargets?.get(t);
|
|
1650
1714
|
a !== void 0 && (a.delete(n), a.size === 0 && this.holderToTargets?.delete(t));
|
|
1651
1715
|
}
|
|
1652
|
-
},
|
|
1716
|
+
}, K = Object.freeze([]), q = [];
|
|
1653
1717
|
//#endregion
|
|
1654
|
-
export { e as Bitmask, t as CommandBuffer, D as ComponentStore, T as DEFAULT_MAX_ENTITIES, n as EventBus, i as IncrementalQuery, a as MigrationError, o as MigrationRegistry,
|
|
1718
|
+
export { e as Bitmask, t as CommandBuffer, D as ComponentStore, T as DEFAULT_MAX_ENTITIES, n as EventBus, i as IncrementalQuery, a as MigrationError, o as MigrationRegistry, P as NULL_REF, d as QueryEngine, f as Schedule, x as Serializer, N as SpatialHash, z as TAG_VALUE, G as World, l as any, B as defineComponent, U as defineEvent, W as defineLocal, H as defineResource, V as defineTag, w as jsonCodec, c as maybe, s as without };
|
|
1655
1719
|
|
|
1656
1720
|
//# sourceMappingURL=index.js.map
|