ecspresso 0.16.0 → 0.16.2

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.
@@ -12,14 +12,30 @@ export interface SpatialEntry3D {
12
12
  halfW: number;
13
13
  halfH: number;
14
14
  halfD: number;
15
+ /** Generation stamp used by query functions to dedup multi-cell hits without a Set. Internal. */
16
+ _lastSeenGen: number;
17
+ /** Rebuild generation when this entry was last inserted. Internal. */
18
+ _aliveGen: number;
15
19
  }
16
20
  export interface SpatialHashGrid3D {
17
21
  cellSize: number;
18
22
  invCellSize: number;
19
- cells: Map<number, number[]>;
20
- entries: Map<number, SpatialEntry3D>;
21
- /** Previous-frame entries held for in-place reuse during rebuild. Internal. */
22
- _entriesPrev: Map<number, SpatialEntry3D>;
23
+ cells: Map<number, SpatialEntry3D[]>;
24
+ /**
25
+ * Dense, indexed by entityId. Holes are `undefined`. Entries from previous
26
+ * rebuilds remain in place for in-place reuse (zero allocation in steady
27
+ * state); liveness is determined by `entry._aliveGen === grid._aliveGen`.
28
+ * Internal — read live entries via `getLiveEntry3D` / `liveEntryCount3D` helpers.
29
+ *
30
+ * High-water-mark grows with max entityId ever inserted; despawned ids
31
+ * leave their slot occupied by a stale entry. Acceptable when the entity
32
+ * manager recycles ids or peak count is bounded.
33
+ */
34
+ entries: (SpatialEntry3D | undefined)[];
35
+ /** Monotonic counter bumped by each `clearGrid3D` call. Internal. */
36
+ _aliveGen: number;
37
+ /** Monotonic counter bumped on each query; entries record their last-seen gen for O(1) dedup. Internal. */
38
+ _queryGen: number;
23
39
  }
24
40
  /**
25
41
  * Hash a cell coordinate triple to a single integer key.
@@ -33,10 +49,11 @@ export declare function createGrid3D(cellSize: number): SpatialHashGrid3D;
33
49
  /**
34
50
  * Prepare the grid for a rebuild.
35
51
  *
36
- * Swaps `entries` with `_entriesPrev` so `insertEntity3D` can reuse existing
37
- * `SpatialEntry3D` objects in place (steady-state rebuilds allocate zero
38
- * entries). Any stale entries left in `_entriesPrev` from the previous
39
- * rebuild are dropped here.
52
+ * Bumps the alive-generation counter so entries inserted prior to this call
53
+ * are implicitly stale (any access via `getLiveEntry3D` / `liveEntryCount3D`
54
+ * filters by the current gen). Existing `SpatialEntry3D` objects remain in
55
+ * the `entries` array for in-place reuse by the next `insertEntity3D`, so
56
+ * steady-state rebuilds allocate zero entries.
40
57
  *
41
58
  * Cell buckets are cleared in place — keys are retained so subsequent
42
59
  * inserts hit the existing array rather than allocating a fresh one.
@@ -48,13 +65,31 @@ export declare function clearGrid3D(grid: SpatialHashGrid3D): void;
48
65
  export declare function insertEntity3D(grid: SpatialHashGrid3D, entityId: number, x: number, y: number, z: number, halfW: number, halfH: number, halfD: number): void;
49
66
  /**
50
67
  * Collect entity IDs from all cells overlapping the given 3D box.
68
+ *
69
+ * Appends to `result` (caller clears/truncates first if reusing). Multi-cell
70
+ * entries are deduplicated via a per-grid generation stamp on each
71
+ * `SpatialEntry3D`.
72
+ *
73
+ * When `minId` is provided, only entries with `entityId > minId` are added —
74
+ * used for symmetric broadphase pair generation.
75
+ */
76
+ export declare function gridQueryBox3D(grid: SpatialHashGrid3D, minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: number[], minId?: number): void;
77
+ /**
78
+ * Collect entity IDs within a sphere. AABB-to-point distance filter against
79
+ * the cells overlapping the sphere's bounding box. Appends to `result`.
80
+ */
81
+ export declare function gridQueryRadius3D(grid: SpatialHashGrid3D, cx: number, cy: number, cz: number, radius: number, result: number[]): void;
82
+ /**
83
+ * Get the current-generation entry for an entityId, or `undefined` if the
84
+ * entity isn't in the index for this rebuild. Stale entries from previous
85
+ * rebuilds remain in `entries` for in-place reuse but are filtered here.
51
86
  */
52
- export declare function gridQueryBox3D(grid: SpatialHashGrid3D, minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: Set<number>): void;
87
+ export declare function getLiveEntry3D(grid: SpatialHashGrid3D, entityId: number): SpatialEntry3D | undefined;
53
88
  /**
54
- * Collect entity IDs within a sphere. Uses box broadphase then
55
- * 3D AABB-to-point distance filter.
89
+ * Count entries inserted in the current rebuild generation. Linear scan
90
+ * intended for tests and diagnostics, not hot paths.
56
91
  */
57
- export declare function gridQueryRadius3D(grid: SpatialHashGrid3D, cx: number, cy: number, cz: number, radius: number, result: Set<number>): void;
92
+ export declare function liveEntryCount3D(grid: SpatialHashGrid3D): number;
58
93
  /**
59
94
  * High-level spatial index API for 3D broadphase queries.
60
95
  *
@@ -65,8 +100,8 @@ export declare function gridQueryRadius3D(grid: SpatialHashGrid3D, cx: number, c
65
100
  export interface SpatialIndex3D {
66
101
  readonly grid: SpatialHashGrid3D;
67
102
  queryBox(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): number[];
68
- queryBoxInto(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: Set<number>): void;
103
+ queryBoxInto(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: number[], minId?: number): void;
69
104
  queryRadius(cx: number, cy: number, cz: number, radius: number): number[];
70
- queryRadiusInto(cx: number, cy: number, cz: number, radius: number, result: Set<number>): void;
105
+ queryRadiusInto(cx: number, cy: number, cz: number, radius: number, result: number[]): void;
71
106
  getEntry(entityId: number): SpatialEntry3D | undefined;
72
107
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecspresso",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",