@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/dist/__tests__/sparse-global-observation.contract.test.d.ts +2 -0
- package/dist/__tests__/sparse-global-observation.contract.test.d.ts.map +1 -0
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/sparse-global-observation.contract.test.ts +30 -0
- package/src/systems/propagate-transforms.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeax/engine-scene",
|
|
3
|
-
"version": "0.1.
|
|
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.
|
|
26
|
-
"@forgeax/engine-math": "0.1.
|
|
27
|
-
"@forgeax/engine-plugin": "0.1.
|
|
28
|
-
"@forgeax/engine-types": "0.1.
|
|
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
|
|
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
|
|
1272
|
+
for (const _span of scratch.dirtyGlobals?.spans().unwrap() ?? []) {
|
|
1273
1273
|
/* observation only */
|
|
1274
1274
|
}
|
|
1275
1275
|
return hierarchy;
|