@forgeax/engine-scene 0.1.34 → 0.1.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeax/engine-scene",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,10 +22,10 @@
22
22
  "LICENSE"
23
23
  ],
24
24
  "dependencies": {
25
- "@forgeax/engine-ecs": "0.1.34",
26
- "@forgeax/engine-math": "0.1.34",
27
- "@forgeax/engine-plugin": "0.1.34",
28
- "@forgeax/engine-types": "0.1.34"
25
+ "@forgeax/engine-ecs": "0.1.35",
26
+ "@forgeax/engine-math": "0.1.35",
27
+ "@forgeax/engine-plugin": "0.1.35",
28
+ "@forgeax/engine-types": "0.1.35"
29
29
  },
30
30
  "forgeax": {
31
31
  "metrics": {
@@ -0,0 +1,30 @@
1
+ import { type EntityHandle, World } from '@forgeax/engine-ecs';
2
+ import { expect, it, vi } from 'vitest';
3
+ import { GlobalTransform, propagateTransforms, Transform } from '../index';
4
+
5
+ const INTERNAL: unique symbol = Symbol.for(
6
+ 'forgeax.ecs.worldInternal',
7
+ ) as unknown as typeof INTERNAL;
8
+
9
+ it('observes sparse derived transforms without walking the complete entity table', () => {
10
+ const world = new World();
11
+ const movers: EntityHandle[] = [];
12
+ for (let index = 0; index < 50_000; index++) {
13
+ const entity = world.spawn({ component: Transform, data: { pos: [index, 0, 0] } }).unwrap();
14
+ if (index < 100) movers.push(entity);
15
+ }
16
+ propagateTransforms(world).unwrap();
17
+ for (const entity of movers) world.set(entity, Transform, { pos: [7, 0, 0] }).unwrap();
18
+ const internal = (world as unknown as { [INTERNAL]: { getGraph(): unknown } })[INTERNAL];
19
+ const graphReads = vi.spyOn(internal, 'getGraph');
20
+ try {
21
+ propagateTransforms(world).unwrap();
22
+ // A row walk reads the graph per entity. Sparse observation must stay
23
+ // proportional to changed ranges and table blocks, not the 50k population.
24
+ expect(graphReads.mock.calls.length).toBeLessThan(5_000);
25
+ for (const entity of movers)
26
+ expect(world.get(entity, GlobalTransform).unwrap().world[12]).toBe(7);
27
+ } finally {
28
+ graphReads.mockRestore();
29
+ }
30
+ });
@@ -1264,12 +1264,12 @@ export function propagateTransforms(world: World): Result<void, SceneError> {
1264
1264
  const pairs = validateTransformPairs(world, scratch);
1265
1265
  if (!pairs.ok) return pairs;
1266
1266
  let globalEdited = false;
1267
- for (const _row of scratch.dirtyGlobals ?? []) globalEdited = true;
1267
+ for (const _span of scratch.dirtyGlobals?.spans().unwrap() ?? []) globalEdited = true;
1268
1268
  const flat = propagateFlat(world, scratch);
1269
1269
  if (!flat.ok) return flat;
1270
1270
  const hierarchy = propagateHierarchy(world, scratch, globalEdited);
1271
1271
  // Consume our own derived publications, while preserving later external edits.
1272
- for (const _row of scratch.dirtyGlobals ?? []) {
1272
+ for (const _span of scratch.dirtyGlobals?.spans().unwrap() ?? []) {
1273
1273
  /* observation only */
1274
1274
  }
1275
1275
  return hierarchy;