ecspresso 0.16.3 → 0.17.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/dist/command-buffer.d.ts +1 -5
- package/dist/ecspresso-builder.d.ts +15 -7
- package/dist/ecspresso.d.ts +4 -5
- package/dist/entity-manager.d.ts +47 -3
- package/dist/event-bus.d.ts +2 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +9 -9
- package/dist/plugins/ai/flocking.js +2 -2
- package/dist/plugins/ai/flocking.js.map +3 -3
- package/dist/plugins/physics/collision.js +2 -2
- package/dist/plugins/physics/collision.js.map +3 -3
- package/dist/plugins/physics/collision3D.js +2 -2
- package/dist/plugins/physics/collision3D.js.map +4 -4
- package/dist/plugins/physics/physics2D.js +2 -2
- package/dist/plugins/physics/physics2D.js.map +3 -3
- package/dist/plugins/physics/physics3D.js +2 -2
- package/dist/plugins/physics/physics3D.js.map +3 -3
- package/dist/plugins/spatial/spatial-index.d.ts +19 -1
- package/dist/plugins/spatial/spatial-index.js +2 -2
- package/dist/plugins/spatial/spatial-index.js.map +3 -3
- package/dist/plugins/spatial/spatial-index3D.d.ts +19 -1
- package/dist/plugins/spatial/spatial-index3D.js +2 -2
- package/dist/plugins/spatial/spatial-index3D.js.map +3 -3
- package/dist/types.d.ts +9 -1
- package/package.json +4 -2
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/plugins/spatial/spatial-index3D.ts", "../src/utils/spatial-hash3D.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Spatial Index 3D Plugin for ECSpresso\n *\n * Provides a uniform-grid spatial hash for broadphase collision detection\n * and proximity queries in 3D. Rebuilds the grid each frame from entity\n * transforms. Replaces O(n²) brute-force with O(n·d) where d = local density.\n *\n * Standalone usage: queryBox / queryRadius for proximity queries.\n * Automatic acceleration: collision3D and physics3D plugins detect the\n * spatialIndex3D resource at runtime and use it for broadphase when present.\n */\n\nimport { definePlugin } from 'ecspresso';\nimport type { SystemPhase } from 'ecspresso';\nimport type { Transform3DComponentTypes } from './transform3D';\nimport {\n\ttype SpatialEntry3D,\n\ttype SpatialHashGrid3D,\n\ttype SpatialIndex3D,\n\tcreateGrid3D,\n\tclearGrid3D,\n\tinsertEntity3D,\n\tgridQueryBox3D,\n\tgridQueryRadius3D,\n\tgetLiveEntry3D,\n} from '../../utils/spatial-hash3D';\n\n// ==================== Collider Component Types ====================\n\n/**\n * 3D axis-aligned bounding box collider component.\n * Defined here (spatial layer) so collision3D can import rather than redefine.\n */\nexport interface AABB3DCollider {\n\twidth: number;\n\theight: number;\n\tdepth: number;\n\toffsetX?: number;\n\toffsetY?: number;\n\toffsetZ?: number;\n}\n\n/**\n * Sphere collider component.\n * Defined here (spatial layer) so collision3D can import rather than redefine.\n */\nexport interface SphereCollider {\n\tradius: number;\n\toffsetX?: number;\n\toffsetY?: number;\n\toffsetZ?: number;\n}\n\nexport interface Spatial3DColliderComponentTypes {\n\taabb3DCollider: AABB3DCollider;\n\tsphereCollider: SphereCollider;\n}\n\n// ==================== Resource API ====================\n\nexport interface SpatialIndex3DResourceTypes {\n\tspatialIndex3D: SpatialIndex3D;\n}\n\nfunction createSpatialIndex3DResource(grid: SpatialHashGrid3D): SpatialIndex3D {\n\treturn {\n\t\tgrid,\n\t\tqueryBox(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): number[] {\n\t\t\tconst out: number[] = [];\n\t\t\tgridQueryBox3D(grid, minX, minY, minZ, maxX, maxY, maxZ, out);\n\t\t\treturn out;\n\t\t},\n\t\tqueryBoxInto(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: number[], minId?: number): void {\n\t\t\tgridQueryBox3D(grid, minX, minY, minZ, maxX, maxY, maxZ, result, minId);\n\t\t},\n\t\tqueryRadius(cx: number, cy: number, cz: number, radius: number): number[] {\n\t\t\tconst out: number[] = [];\n\t\t\tgridQueryRadius3D(grid, cx, cy, cz, radius, out);\n\t\t\treturn out;\n\t\t},\n\t\tqueryRadiusInto(cx: number, cy: number, cz: number, radius: number, result: number[]): void {\n\t\t\tgridQueryRadius3D(grid, cx, cy, cz, radius, result);\n\t\t},\n\t\tgetEntry(entityId: number): SpatialEntry3D | undefined {\n\t\t\treturn getLiveEntry3D(grid, entityId);\n\t\t},\n\t};\n}\n\n// ==================== Component Types ====================\n\ntype SpatialIndex3DComponentTypes = Transform3DComponentTypes & Spatial3DColliderComponentTypes;\n\n// ==================== Plugin Options ====================\n\nexport type SpatialIndex3DPhase = 'fixedUpdate' | 'postUpdate';\ntype SpatialIndex3DLabel = `spatial-index3D-rebuild-${SpatialIndex3DPhase}`;\n\nexport interface SpatialIndex3DPluginOptions<G extends string = 'spatialIndex3D'> {\n\t/** Cell size for the spatial hash grid (default: 64) */\n\tcellSize?: number;\n\t/** System group name (default: 'spatialIndex3D') */\n\tsystemGroup?: G;\n\t/** Priority for rebuild systems (default: 2000, before collision) */\n\tpriority?: number;\n\t
|
|
5
|
+
"/**\n * Spatial Index 3D Plugin for ECSpresso\n *\n * Provides a uniform-grid spatial hash for broadphase collision detection\n * and proximity queries in 3D. Rebuilds the grid each frame from entity\n * transforms. Replaces O(n²) brute-force with O(n·d) where d = local density.\n *\n * Standalone usage: queryBox / queryRadius for proximity queries.\n * Automatic acceleration: collision3D and physics3D plugins detect the\n * spatialIndex3D resource at runtime and use it for broadphase when present.\n */\n\nimport { definePlugin } from 'ecspresso';\nimport type { SystemPhase } from 'ecspresso';\nimport type { Transform3DComponentTypes } from './transform3D';\nimport {\n\ttype SpatialEntry3D,\n\ttype SpatialHashGrid3D,\n\ttype SpatialIndex3D,\n\tcreateGrid3D,\n\tclearGrid3D,\n\tinsertEntity3D,\n\tgridQueryBox3D,\n\tgridQueryRadius3D,\n\tgetLiveEntry3D,\n} from '../../utils/spatial-hash3D';\n\n// ==================== Collider Component Types ====================\n\n/**\n * 3D axis-aligned bounding box collider component.\n * Defined here (spatial layer) so collision3D can import rather than redefine.\n */\nexport interface AABB3DCollider {\n\twidth: number;\n\theight: number;\n\tdepth: number;\n\toffsetX?: number;\n\toffsetY?: number;\n\toffsetZ?: number;\n}\n\n/**\n * Sphere collider component.\n * Defined here (spatial layer) so collision3D can import rather than redefine.\n */\nexport interface SphereCollider {\n\tradius: number;\n\toffsetX?: number;\n\toffsetY?: number;\n\toffsetZ?: number;\n}\n\nexport interface Spatial3DColliderComponentTypes {\n\taabb3DCollider: AABB3DCollider;\n\tsphereCollider: SphereCollider;\n}\n\n// ==================== Resource API ====================\n\nexport interface SpatialIndex3DResourceTypes {\n\tspatialIndex3D: SpatialIndex3D;\n}\n\nfunction createSpatialIndex3DResource(grid: SpatialHashGrid3D): SpatialIndex3D {\n\treturn {\n\t\tgrid,\n\t\tqueryBox(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): number[] {\n\t\t\tconst out: number[] = [];\n\t\t\tgridQueryBox3D(grid, minX, minY, minZ, maxX, maxY, maxZ, out);\n\t\t\treturn out;\n\t\t},\n\t\tqueryBoxInto(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: number[], minId?: number): void {\n\t\t\tgridQueryBox3D(grid, minX, minY, minZ, maxX, maxY, maxZ, result, minId);\n\t\t},\n\t\tqueryRadius(cx: number, cy: number, cz: number, radius: number): number[] {\n\t\t\tconst out: number[] = [];\n\t\t\tgridQueryRadius3D(grid, cx, cy, cz, radius, out);\n\t\t\treturn out;\n\t\t},\n\t\tqueryRadiusInto(cx: number, cy: number, cz: number, radius: number, result: number[]): void {\n\t\t\tgridQueryRadius3D(grid, cx, cy, cz, radius, result);\n\t\t},\n\t\tgetEntry(entityId: number): SpatialEntry3D | undefined {\n\t\t\treturn getLiveEntry3D(grid, entityId);\n\t\t},\n\t};\n}\n\n// ==================== Component Types ====================\n\ntype SpatialIndex3DComponentTypes = Transform3DComponentTypes & Spatial3DColliderComponentTypes;\n\n// ==================== Plugin Options ====================\n\nexport type SpatialIndex3DPhase = 'fixedUpdate' | 'postUpdate';\ntype SpatialIndex3DLabel = `spatial-index3D-rebuild-${SpatialIndex3DPhase}`;\n\nexport interface SpatialIndex3DPluginOptions<G extends string = 'spatialIndex3D'> {\n\t/** Cell size for the spatial hash grid (default: 64) */\n\tcellSize?: number;\n\t/** System group name (default: 'spatialIndex3D') */\n\tsystemGroup?: G;\n\t/** Priority for rebuild systems (default: 2000, before collision) */\n\tpriority?: number;\n\t/**\n\t * Phases to register rebuild systems in (default: ['fixedUpdate', 'postUpdate']).\n\t *\n\t * When both phases are registered, the `postUpdate` rebuild is\n\t * automatically skipped on cycles where:\n\t * 1. The `fixedUpdate` rebuild already ran this cycle, AND\n\t * 2. No entity hierarchy exists.\n\t *\n\t * In flat-hierarchy scenes `transform3d-propagation` copies\n\t * `localTransform3D → worldTransform3D` unchanged, so the postUpdate\n\t * grid would duplicate the fixedUpdate one. The skip is automatic\n\t * and re-engages once any parent relationship is set, or whenever\n\t * `fixedUpdate` doesn't run that cycle (sub-fixed-DT frames).\n\t *\n\t * Edge case: if you write to `worldTransform3D` directly between\n\t * phases without using `transform3d-propagation` or entity hierarchy,\n\t * the auto-skip will leave your writes unindexed. Set\n\t * `phases: ['postUpdate']` explicitly to bypass the auto-skip.\n\t */\n\tphases?: ReadonlyArray<SpatialIndex3DPhase>;\n}\n\n// ==================== Plugin Factory ====================\n\n/**\n * Create a 3D spatial index plugin for ECSpresso.\n *\n * Provides a uniform-grid spatial hash that accelerates 3D collision detection.\n * When installed alongside the collision3D or physics3D plugins, they\n * automatically use the spatial index for broadphase instead of O(n²)\n * brute-force.\n *\n * Also provides proximity query methods for game logic (e.g. \"find all\n * enemies within 200 units\").\n *\n * @example\n * ```typescript\n * const ecs = ECSpresso.create()\n * .withPlugin(createTransform3DPlugin())\n * .withPlugin(createCollision3DPlugin({ layers }))\n * .withPlugin(createSpatialIndex3DPlugin({ cellSize: 128 }))\n * .build();\n *\n * // Proximity query in a system:\n * const si = ecs.getResource('spatialIndex3D');\n * const nearby = si.queryRadius(playerX, playerY, playerZ, 200);\n * ```\n */\nexport function createSpatialIndex3DPlugin<G extends string = 'spatialIndex3D'>(\n\toptions?: SpatialIndex3DPluginOptions<G>,\n) {\n\tconst {\n\t\tcellSize = 64,\n\t\tsystemGroup = 'spatialIndex3D',\n\t\tpriority = 2000,\n\t\tphases = ['fixedUpdate', 'postUpdate'] as const,\n\t} = options ?? {};\n\n\tconst grid = createGrid3D(cellSize);\n\tconst resource = createSpatialIndex3DResource(grid);\n\n\treturn definePlugin('spatialIndex3D')\n\t\t.withComponentTypes<SpatialIndex3DComponentTypes>()\n\t\t.withResourceTypes<SpatialIndex3DResourceTypes>()\n\t\t.withLabels<SpatialIndex3DLabel>()\n\t\t.withGroups<G>()\n\t\t.install((world) => {\n\t\t\tworld.addResource('spatialIndex3D', resource);\n\n\t\t\t// Flag flipped true by the fixedUpdate rebuild; checked + reset by the\n\t\t\t// postUpdate rebuild to detect whether fixedUpdate ran this cycle.\n\t\t\t// Lets postUpdate auto-skip when its grid would duplicate fixedUpdate's\n\t\t\t// in flat-hierarchy scenes — without breaking sub-fixed-DT frames\n\t\t\t// where only postUpdate runs.\n\t\t\tlet fixedRebuildRanThisCycle = false;\n\n\t\t\t// Register a rebuild system for each requested phase\n\t\t\tfor (const phase of phases) {\n\t\t\t\tconst transformComponent = phase === 'fixedUpdate' ? 'localTransform3D' : 'worldTransform3D';\n\t\t\t\tconst isPostUpdate = phase === 'postUpdate';\n\n\t\t\t\tworld\n\t\t\t\t\t.addSystem(`spatial-index3D-rebuild-${phase}`)\n\t\t\t\t\t.setPriority(priority)\n\t\t\t\t\t.inPhase(phase as SystemPhase)\n\t\t\t\t\t.inGroup(systemGroup)\n\t\t\t\t\t.addQuery('aabbWith', {\n\t\t\t\t\t\twith: [transformComponent, 'aabb3DCollider'],\n\t\t\t\t\t})\n\t\t\t\t\t.addQuery('sphereOnly', {\n\t\t\t\t\t\twith: [transformComponent, 'sphereCollider'],\n\t\t\t\t\t\twithout: ['aabb3DCollider'],\n\t\t\t\t\t})\n\t\t\t\t\t.runWhenEmpty()\n\t\t\t\t\t.setProcess(({ queries, ecs }) => {\n\t\t\t\t\t\tif (isPostUpdate) {\n\t\t\t\t\t\t\tconst ranFixed = fixedRebuildRanThisCycle;\n\t\t\t\t\t\t\tfixedRebuildRanThisCycle = false;\n\t\t\t\t\t\t\t// Skip only when fixedUpdate populated the grid this\n\t\t\t\t\t\t\t// cycle AND no hierarchy exists (so worldTransform3D\n\t\t\t\t\t\t\t// equals localTransform3D — identical grid data).\n\t\t\t\t\t\t\tif (ranFixed && !ecs.entityManager.hasHierarchy) return;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tclearGrid3D(grid);\n\n\t\t\t\t\t\t// AABB-precedence: aabbWith covers both aabb-only AND\n\t\t\t\t\t\t// entities carrying both colliders. Sphere-only is its own\n\t\t\t\t\t\t// query. Matches collision3D / physics3D semantic.\n\t\t\t\t\t\tfor (const entity of queries.aabbWith) {\n\t\t\t\t\t\t\tconst transform = entity.components[transformComponent];\n\t\t\t\t\t\t\tconst { aabb3DCollider } = entity.components;\n\t\t\t\t\t\t\tinsertEntity3D(\n\t\t\t\t\t\t\t\tgrid, entity.id,\n\t\t\t\t\t\t\t\ttransform.x + (aabb3DCollider.offsetX ?? 0),\n\t\t\t\t\t\t\t\ttransform.y + (aabb3DCollider.offsetY ?? 0),\n\t\t\t\t\t\t\t\ttransform.z + (aabb3DCollider.offsetZ ?? 0),\n\t\t\t\t\t\t\t\taabb3DCollider.width / 2, aabb3DCollider.height / 2, aabb3DCollider.depth / 2,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const entity of queries.sphereOnly) {\n\t\t\t\t\t\t\tconst transform = entity.components[transformComponent];\n\t\t\t\t\t\t\tconst { sphereCollider } = entity.components;\n\t\t\t\t\t\t\tconst r = sphereCollider.radius;\n\t\t\t\t\t\t\tinsertEntity3D(\n\t\t\t\t\t\t\t\tgrid, entity.id,\n\t\t\t\t\t\t\t\ttransform.x + (sphereCollider.offsetX ?? 0),\n\t\t\t\t\t\t\t\ttransform.y + (sphereCollider.offsetY ?? 0),\n\t\t\t\t\t\t\t\ttransform.z + (sphereCollider.offsetZ ?? 0),\n\t\t\t\t\t\t\t\tr, r, r,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!isPostUpdate) fixedRebuildRanThisCycle = true;\n\t\t\t\t\t});\n\t\t\t}\n\t\t});\n}\n",
|
|
6
6
|
"/**\n * Spatial Hash Grid 3D\n *\n * Uniform-grid spatial hash for broadphase collision detection and\n * proximity queries in 3D. Pure data structure, no ECS dependencies.\n */\n\n// ==================== Data Structures ====================\n\nexport interface SpatialEntry3D {\n\tentityId: number;\n\tx: number;\n\ty: number;\n\tz: number;\n\thalfW: number;\n\thalfH: number;\n\thalfD: number;\n\t/** Generation stamp used by query functions to dedup multi-cell hits without a Set. Internal. */\n\t_lastSeenGen: number;\n\t/** Rebuild generation when this entry was last inserted. Internal. */\n\t_aliveGen: number;\n}\n\n/**\n * A cell bucket — entries plus the alive-gen at which the bucket was last\n * filled. Buckets are reset lazily on the next insert in a new generation\n * (see `insertEntity3D`); queries skip buckets whose `_gen` is stale.\n *\n * Internal — exposed only through `SpatialHashGrid3D.cells`.\n */\ninterface CellBucket3D extends Array<SpatialEntry3D> {\n\t_gen: number;\n}\n\nexport interface SpatialHashGrid3D {\n\tcellSize: number;\n\tinvCellSize: number;\n\tcells: Map<number, CellBucket3D>;\n\t/**\n\t * Dense, indexed by entityId. Holes are `undefined`. Entries from previous\n\t * rebuilds remain in place for in-place reuse (zero allocation in steady\n\t * state); liveness is determined by `entry._aliveGen === grid._aliveGen`.\n\t * Internal — read live entries via `getLiveEntry3D` / `liveEntryCount3D` helpers.\n\t *\n\t * High-water-mark grows with max entityId ever inserted; despawned ids\n\t * leave their slot occupied by a stale entry. Acceptable when the entity\n\t * manager recycles ids or peak count is bounded.\n\t */\n\tentries: (SpatialEntry3D | undefined)[];\n\t/** Monotonic counter bumped by each `clearGrid3D` call. Internal. */\n\t_aliveGen: number;\n\t/** Monotonic counter bumped on each query; entries record their last-seen gen for O(1) dedup. Internal. */\n\t_queryGen: number;\n}\n\n// ==================== Pure Functions ====================\n\n/**\n * Hash a cell coordinate triple to a single integer key.\n * Uses large-prime XOR to distribute values.\n */\nexport function hashCell3D(cx: number, cy: number, cz: number): number {\n\t// Large primes for spatial hashing distribution\n\treturn (cx * 73856093) ^ (cy * 19349663) ^ (cz * 83492791);\n}\n\n/**\n * Create a new empty 3D spatial hash grid.\n */\nexport function createGrid3D(cellSize: number): SpatialHashGrid3D {\n\treturn {\n\t\tcellSize,\n\t\tinvCellSize: 1 / cellSize,\n\t\tcells: new Map(),\n\t\tentries: [],\n\t\t_aliveGen: 0,\n\t\t_queryGen: 0,\n\t};\n}\n\n/**\n * Prepare the grid for a rebuild.\n *\n * O(1): bumps the alive-generation counter so entries inserted prior to this\n * call are implicitly stale. `getLiveEntry3D` / `liveEntryCount3D` filter\n * entries by the current gen; queries skip buckets whose own `_gen` lags\n * behind the alive gen; `insertEntity3D` resets a bucket's `length` lazily\n * the first time it is touched in a new generation.\n *\n * Existing `SpatialEntry3D` objects and `CellBucket3D` arrays remain in\n * place for reuse, so steady-state rebuilds allocate zero entries and zero\n * buckets, regardless of how many cells have ever been touched.\n */\nexport function clearGrid3D(grid: SpatialHashGrid3D): void {\n\tgrid._aliveGen++;\n}\n\n/**\n * Insert an entity into all overlapping cells of the grid.\n */\nexport function insertEntity3D(\n\tgrid: SpatialHashGrid3D,\n\tentityId: number,\n\tx: number,\n\ty: number,\n\tz: number,\n\thalfW: number,\n\thalfH: number,\n\thalfD: number,\n): void {\n\tconst gen = grid._aliveGen;\n\tconst existing = grid.entries[entityId];\n\tlet entry: SpatialEntry3D;\n\tif (existing) {\n\t\texisting.x = x;\n\t\texisting.y = y;\n\t\texisting.z = z;\n\t\texisting.halfW = halfW;\n\t\texisting.halfH = halfH;\n\t\texisting.halfD = halfD;\n\t\texisting._aliveGen = gen;\n\t\tentry = existing;\n\t} else {\n\t\tentry = { entityId, x, y, z, halfW, halfH, halfD, _lastSeenGen: 0, _aliveGen: gen };\n\t\tgrid.entries[entityId] = entry;\n\t}\n\n\tconst inv = grid.invCellSize;\n\tconst minCX = Math.floor((x - halfW) * inv);\n\tconst maxCX = Math.floor((x + halfW) * inv);\n\tconst minCY = Math.floor((y - halfH) * inv);\n\tconst maxCY = Math.floor((y + halfH) * inv);\n\tconst minCZ = Math.floor((z - halfD) * inv);\n\tconst maxCZ = Math.floor((z + halfD) * inv);\n\n\tfor (let cx = minCX; cx <= maxCX; cx++) {\n\t\tfor (let cy = minCY; cy <= maxCY; cy++) {\n\t\t\tfor (let cz = minCZ; cz <= maxCZ; cz++) {\n\t\t\t\tconst key = hashCell3D(cx, cy, cz);\n\t\t\t\tconst bucket = grid.cells.get(key);\n\t\t\t\tif (bucket && bucket._gen === gen) {\n\t\t\t\t\t// Hot path: bucket already populated this generation.\n\t\t\t\t\tbucket.push(entry);\n\t\t\t\t} else if (bucket) {\n\t\t\t\t\t// First touch in this generation — drop stale entries from prior rebuilds.\n\t\t\t\t\tbucket.length = 0;\n\t\t\t\t\tbucket._gen = gen;\n\t\t\t\t\tbucket.push(entry);\n\t\t\t\t} else {\n\t\t\t\t\tconst fresh = [entry] as CellBucket3D;\n\t\t\t\t\tfresh._gen = gen;\n\t\t\t\t\tgrid.cells.set(key, fresh);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Collect entity IDs from all cells overlapping the given 3D box.\n *\n * Appends to `result` (caller clears/truncates first if reusing). Multi-cell\n * entries are deduplicated via a per-grid generation stamp on each\n * `SpatialEntry3D`.\n *\n * When `minId` is provided, only entries with `entityId > minId` are added —\n * used for symmetric broadphase pair generation.\n */\nexport function gridQueryBox3D(\n\tgrid: SpatialHashGrid3D,\n\tminX: number,\n\tminY: number,\n\tminZ: number,\n\tmaxX: number,\n\tmaxY: number,\n\tmaxZ: number,\n\tresult: number[],\n\tminId: number = -1,\n): void {\n\tconst inv = grid.invCellSize;\n\tconst minCX = Math.floor(minX * inv);\n\tconst maxCX = Math.floor(maxX * inv);\n\tconst minCY = Math.floor(minY * inv);\n\tconst maxCY = Math.floor(maxY * inv);\n\tconst minCZ = Math.floor(minZ * inv);\n\tconst maxCZ = Math.floor(maxZ * inv);\n\n\tconst gen = ++grid._queryGen;\n\tconst aliveGen = grid._aliveGen;\n\n\tfor (let cx = minCX; cx <= maxCX; cx++) {\n\t\tfor (let cy = minCY; cy <= maxCY; cy++) {\n\t\t\tfor (let cz = minCZ; cz <= maxCZ; cz++) {\n\t\t\t\tconst bucket = grid.cells.get(hashCell3D(cx, cy, cz));\n\t\t\t\tif (!bucket || bucket._gen !== aliveGen) continue;\n\t\t\t\tfor (const entry of bucket) {\n\t\t\t\t\tif (entry.entityId <= minId || entry._lastSeenGen === gen) continue;\n\t\t\t\t\tentry._lastSeenGen = gen;\n\t\t\t\t\tresult.push(entry.entityId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Collect entity IDs within a sphere. AABB-to-point distance filter against\n * the cells overlapping the sphere's bounding box. Appends to `result`.\n */\nexport function gridQueryRadius3D(\n\tgrid: SpatialHashGrid3D,\n\tcx: number,\n\tcy: number,\n\tcz: number,\n\tradius: number,\n\tresult: number[],\n): void {\n\tconst rSq = radius * radius;\n\tconst inv = grid.invCellSize;\n\tconst minCX = Math.floor((cx - radius) * inv);\n\tconst maxCX = Math.floor((cx + radius) * inv);\n\tconst minCY = Math.floor((cy - radius) * inv);\n\tconst maxCY = Math.floor((cy + radius) * inv);\n\tconst minCZ = Math.floor((cz - radius) * inv);\n\tconst maxCZ = Math.floor((cz + radius) * inv);\n\n\tconst gen = ++grid._queryGen;\n\tconst aliveGen = grid._aliveGen;\n\n\tfor (let icx = minCX; icx <= maxCX; icx++) {\n\t\tfor (let icy = minCY; icy <= maxCY; icy++) {\n\t\t\tfor (let icz = minCZ; icz <= maxCZ; icz++) {\n\t\t\t\tconst bucket = grid.cells.get(hashCell3D(icx, icy, icz));\n\t\t\t\tif (!bucket || bucket._gen !== aliveGen) continue;\n\t\t\t\tfor (const entry of bucket) {\n\t\t\t\t\tif (entry._lastSeenGen === gen) continue;\n\t\t\t\t\tentry._lastSeenGen = gen;\n\n\t\t\t\t\tconst closestX = Math.max(entry.x - entry.halfW, Math.min(cx, entry.x + entry.halfW));\n\t\t\t\t\tconst closestY = Math.max(entry.y - entry.halfH, Math.min(cy, entry.y + entry.halfH));\n\t\t\t\t\tconst closestZ = Math.max(entry.z - entry.halfD, Math.min(cz, entry.z + entry.halfD));\n\t\t\t\t\tconst dx = cx - closestX;\n\t\t\t\t\tconst dy = cy - closestY;\n\t\t\t\t\tconst dz = cz - closestZ;\n\n\t\t\t\t\tif (dx * dx + dy * dy + dz * dz <= rSq) {\n\t\t\t\t\t\tresult.push(entry.entityId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Get the current-generation entry for an entityId, or `undefined` if the\n * entity isn't in the index for this rebuild. Stale entries from previous\n * rebuilds remain in `entries` for in-place reuse but are filtered here.\n */\nexport function getLiveEntry3D(grid: SpatialHashGrid3D, entityId: number): SpatialEntry3D | undefined {\n\tconst entry = grid.entries[entityId];\n\tif (!entry || entry._aliveGen !== grid._aliveGen) return undefined;\n\treturn entry;\n}\n\n/**\n * Count entries inserted in the current rebuild generation. Linear scan —\n * intended for tests and diagnostics, not hot paths.\n */\nexport function liveEntryCount3D(grid: SpatialHashGrid3D): number {\n\tconst gen = grid._aliveGen;\n\tlet n = 0;\n\tfor (const entry of grid.entries) {\n\t\tif (entry && entry._aliveGen === gen) n++;\n\t}\n\treturn n;\n}\n\n// ==================== SpatialIndex3D Interface ====================\n\n/**\n * High-level spatial index API for 3D broadphase queries.\n *\n * Defined here (the utility layer) so that narrowphase3D can accept it\n * without importing the ECS plugin. The spatial-index3D plugin creates\n * an object that implements this interface and registers it as a resource.\n */\nexport interface SpatialIndex3D {\n\treadonly grid: SpatialHashGrid3D;\n\tqueryBox(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number): number[];\n\tqueryBoxInto(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, result: number[], minId?: number): void;\n\tqueryRadius(cx: number, cy: number, cz: number, radius: number): number[];\n\tqueryRadiusInto(cx: number, cy: number, cz: number, radius: number, result: number[]): void;\n\tgetEntry(entityId: number): SpatialEntry3D | undefined;\n}\n"
|
|
7
7
|
],
|
|
8
|
-
"mappings": "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
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "C91D70E729A54E7764756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -59,6 +59,10 @@ export interface QueryConfig<ComponentTypes, WithComponents extends keyof Compon
|
|
|
59
59
|
* entity, catching accidental writes at compile time.
|
|
60
60
|
*/
|
|
61
61
|
mutates?: ReadonlyArray<MutatesComponents>;
|
|
62
|
+
/** @internal Pre-resolved component indices for `changed:`, populated at system registration. */
|
|
63
|
+
_changedIdx?: ReadonlyArray<number>;
|
|
64
|
+
/** @internal Pre-resolved component indices for `mutates:`, populated at system registration. */
|
|
65
|
+
_mutatesIdx?: ReadonlyArray<number>;
|
|
62
66
|
}
|
|
63
67
|
/**
|
|
64
68
|
* Utility type to derive the entity type that would result from a query definition.
|
|
@@ -104,6 +108,10 @@ export type QueryDefinition<ComponentTypes extends Record<string, any>, WithComp
|
|
|
104
108
|
* are narrowed to `Readonly<T>` on the iteration entity type.
|
|
105
109
|
*/
|
|
106
110
|
mutates?: ReadonlyArray<MutatesComponents>;
|
|
111
|
+
/** @internal Pre-resolved component indices for `changed:`, populated at system registration. */
|
|
112
|
+
_changedIdx?: ReadonlyArray<number>;
|
|
113
|
+
/** @internal Pre-resolved component indices for `mutates:`, populated at system registration. */
|
|
114
|
+
_mutatesIdx?: ReadonlyArray<number>;
|
|
107
115
|
};
|
|
108
116
|
/**
|
|
109
117
|
* Helper function to create a query definition with proper type inference.
|
|
@@ -240,7 +248,7 @@ export interface System<Cfg extends WorldConfig = EmptyConfig, WithComponents ex
|
|
|
240
248
|
*/
|
|
241
249
|
_autoMarkPairs?: ReadonlyArray<{
|
|
242
250
|
queryName: string;
|
|
243
|
-
|
|
251
|
+
mutatesIdx: ReadonlyArray<number>;
|
|
244
252
|
kind: 'list' | 'singleton';
|
|
245
253
|
}> | null;
|
|
246
254
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecspresso",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -177,6 +177,7 @@
|
|
|
177
177
|
"@types/react-dom": "^19.2.3",
|
|
178
178
|
"@types/three": "^0.184.0",
|
|
179
179
|
"howler": "^2.2.4",
|
|
180
|
+
"phaser": "^4.1.0",
|
|
180
181
|
"pixi.js": "^8.18.1",
|
|
181
182
|
"react": "^19.2.5",
|
|
182
183
|
"react-dom": "^19.2.5",
|
|
@@ -219,7 +220,8 @@
|
|
|
219
220
|
"check:types": "bun tsc --noEmit --skipLibCheck",
|
|
220
221
|
"check": "bun run check:types && bun test",
|
|
221
222
|
"examples": "bun ./examples/serve-examples.ts",
|
|
222
|
-
"bench": "bun bench/narrowphase.bench.ts && bun bench/ecs-physics.bench.ts --spatial && bun bench/ecs-physics.bench.ts --no-spatial",
|
|
223
|
+
"bench": "bun bench/narrowphase.bench.ts && bun bench/ecs-physics.bench.ts --spatial && bun bench/ecs-physics.bench.ts --no-spatial && bun bench/ecs-physics3D.bench.ts --spatial && bun bench/ecs-physics3D.bench.ts --no-spatial",
|
|
224
|
+
"bench:ecs3D": "bun bench/ecs-physics3D.bench.ts",
|
|
223
225
|
"bench:narrowphase": "bun bench/narrowphase.bench.ts",
|
|
224
226
|
"bench:ecs": "bun bench/ecs-physics.bench.ts",
|
|
225
227
|
"docs": "typedoc && bun scripts/build-examples.ts && bun scripts/build-docs-index.ts",
|