83 lines
3.5 KiB
Markdown
83 lines
3.5 KiB
Markdown
# Loaded Resource Discovery 01
|
|
|
|
## Question
|
|
|
|
Can villagers resolve finite resource anchors spread across a larger Terrain3D
|
|
world without scanning every loaded `ResourceNode`, while selecting exactly the
|
|
same target as the existing distance/risk/comfort/priority score?
|
|
|
|
## Reviewed workload
|
|
|
|
- Godot: `4.7-stable (official)`;
|
|
- host: Apple M1 Max, 64 GB;
|
|
- benchmark seed: `17331`;
|
|
- loaded resources: 18, 180, and 1,800;
|
|
- 400 deterministic target resolutions per sample;
|
|
- seven fresh timing samples per case;
|
|
- 20 m horizontal source spacing with varied terrain-like height, safety risk,
|
|
comfort distance, discovery priority, and deterministic disabled sources;
|
|
- each query performs the real availability check, score, reservation, and
|
|
release through `ActionTargetResolver` and `ResourceStateRecord`.
|
|
|
|
The linear reference reproduces the previous `ResourceNode.get_all()` scan.
|
|
The spatial path uses the production `ActiveWorldAdapter` and its 24 m
|
|
resource-specific horizontal grid. Fixture construction, rendering, navigation
|
|
pathfinding, simulation ticks, and serialization are excluded.
|
|
|
|
## Results
|
|
|
|
| Loaded anchors | Linear µs/query | Spatial µs/query | Speedup | Average inspected | Reduction |
|
|
| ---: | ---: | ---: | ---: | ---: | ---: |
|
|
| 18 | 65.04 | 33.26 | 1.96x | 18 → 3.705 | 79.42% |
|
|
| 180 | 589.03 | 38.83 | 15.17x | 180 → 4.375 | 97.57% |
|
|
| 1,800 | 6,448.00 | 46.94 | 137.37x | 1,800 → 4.445 | 99.75% |
|
|
|
|
Every spatial sample produced the same selected-target checksum as its linear
|
|
reference. The raw samples are in
|
|
[`loaded_resource_discovery_01.json`](loaded_resource_discovery_01.json).
|
|
|
|
These are local workload measurements, not portable performance promises. The
|
|
important shape is that ordinary local queries remain near four inspected
|
|
anchors while the loaded set grows by 100x.
|
|
|
|
## Exactness contract
|
|
|
|
`ActionTargetResolver` queries successively larger grid radii. It may stop only
|
|
when the best possible score of every farther anchor is strictly worse than the
|
|
current winner. The lower bound uses the loaded action's authoritative maximum
|
|
comfort distance, minimum safety risk, and maximum discovery priority. Stable
|
|
registration order preserves the former first-loaded tie behavior.
|
|
|
|
Unavailable, depleted, and reserved state remains authoritative in
|
|
`ResourceStateRecord`; the grid indexes only loaded IDs, interaction positions,
|
|
and disposable score bounds. Unloading removes an anchor without deleting its
|
|
state. Rebinding the same ID or moving a loaded anchor refreshes the index.
|
|
|
|
One focused regression also gives the farthest test source an extreme priority.
|
|
The query expands beyond its local cells and selects that source exactly as the
|
|
linear scan does, proving that the common local fast path is not a hard range
|
|
cutoff.
|
|
|
|
## Decision
|
|
|
|
Keep the resource-specific grid inside `ActiveWorldAdapter`. It has one real
|
|
consumer, preserves current gameplay, and directly supports larger authored
|
|
source fields. Do not generalize it into a people/building/event index or a
|
|
simulation-LOD framework yet.
|
|
|
|
Terrain3D foliage instances remain decorative unless an intentional stable-ID
|
|
`ResourceNode` anchor binds simulation-owned state. A later placement workflow
|
|
can author those anchors alongside visual instancing without making every tree
|
|
an authoritative resource.
|
|
|
|
## Capture command
|
|
|
|
```bash
|
|
/Applications/Godot.app/Contents/MacOS/Godot \
|
|
--headless --path "$PWD" \
|
|
--script res://tools/benchmark_loaded_resource_discovery.gd -- \
|
|
--queries=400 --samples=7 \
|
|
--host-label=Apple_M1_Max_64_GB \
|
|
--output=res://docs/benchmarks/loaded_resource_discovery_01.json
|
|
```
|