feat: index loaded resource discovery
This commit is contained in:
@@ -47,6 +47,10 @@ SimulationManager tick
|
||||
|
||||
- reads target metadata from ActionDefinition;
|
||||
- consumes active-world facts through ActiveWorldAdapter;
|
||||
- expands resource queries through nearby grid ranges and prunes farther cells
|
||||
only when authoritative risk/comfort/priority bounds prove they cannot win;
|
||||
- preserves the former registration-order tie behavior and keeps a linear
|
||||
compatibility path for isolated adapters;
|
||||
- checks simulation-owned ResourceStateRecord availability;
|
||||
- reserves and returns stable resource target IDs;
|
||||
- skips full-capacity activity sites based on authoritative NPC target claims;
|
||||
@@ -55,7 +59,10 @@ SimulationManager tick
|
||||
|
||||
### ActiveWorldAdapter
|
||||
|
||||
- exposes loaded resource interaction positions;
|
||||
- owns the disposable `LoadedResourceSpatialIndex` of loaded stable-ID resource
|
||||
interaction positions;
|
||||
- refreshes the index as ResourceNodes enter, leave, rebind authoritative
|
||||
state, or move;
|
||||
- exposes loaded storage and activity-site interaction positions;
|
||||
- exposes activity-site capacity as an active-world fact;
|
||||
- contains active-world query facts, not persistent mutable authority;
|
||||
@@ -77,17 +84,17 @@ targets, and translates presentation callbacks into simulation transitions.
|
||||
It also owns one disposable `SimulationPopulationView`, rebuilt at tick start
|
||||
and refreshed after each NPC advances so interleaved decision semantics remain
|
||||
unchanged.
|
||||
The manager publishes the latest `ActionSelectionResult` for presentation; the UI
|
||||
does not recompute decisions. Each idle selection re-derives the capable helper
|
||||
instead of consulting persisted assignment state. At completion it atomically
|
||||
pays any definition-backed stored-resource cost before applying the action
|
||||
effect. A late shortfall suppresses the effect and records a `task_blocked`
|
||||
fact. The manager also captures actor/nearby knowledge before forwarding newly
|
||||
recorded events into `RelationshipSystem`. When an NPC arrives beside a worker
|
||||
at the same non-storage activity site, the manager may transfer one direct
|
||||
known fact and applies its consequence only to that newly informed listener. An
|
||||
open opportunity's exact trigger receives bounded priority in that conversation
|
||||
before normal lasting/recent ranking. It exposes
|
||||
The manager publishes the latest `ActionSelectionResult` for presentation; the
|
||||
UI does not recompute decisions. Each idle selection re-derives the capable
|
||||
helper instead of consulting persisted assignment state. At completion it
|
||||
atomically pays any definition-backed stored-resource cost before applying the
|
||||
action effect. A late shortfall suppresses the effect and records a
|
||||
`task_blocked` fact. The manager also captures actor/nearby knowledge before
|
||||
forwarding newly recorded events into `RelationshipSystem`. When an NPC arrives
|
||||
beside a worker at the same non-storage activity site, the manager may transfer
|
||||
one direct known fact and applies its consequence only to that newly informed
|
||||
listener. An open opportunity's exact trigger receives bounded priority in
|
||||
that conversation before normal lasting/recent ranking. It exposes
|
||||
knowledge, provenance, relationship, and cause queries without moving social
|
||||
authority into UI. After consequences are known, it protects current causal
|
||||
facts, enforces the recent-memory cap, and runs age review from authoritative
|
||||
|
||||
@@ -22,6 +22,7 @@ SimulationClock
|
||||
-> VillageOpportunitySystem projects one known unresolved need
|
||||
-> WorldViewManager presents travel, NPC state, and world-state cues
|
||||
-> ActiveWorldAdapter supplies loaded-world positions/capacity
|
||||
-> LoadedResourceSpatialIndex bounds finite-anchor discovery
|
||||
-> NpcVisual performs local navigation, animation, and transient reactions
|
||||
-> PantryStockVisual derives physical stock arrangement from storage state
|
||||
```
|
||||
@@ -62,6 +63,13 @@ would otherwise obscure that lifecycle:
|
||||
- `simulation/definitions/` owns stable IDs and immutable action/profession
|
||||
definitions.
|
||||
|
||||
`world/resource_nodes/LoadedResourceSpatialIndex.gd` is a focused disposable
|
||||
acceleration structure owned by `ActiveWorldAdapter`. It indexes loaded
|
||||
interaction positions by action and horizontal cell, plus authoritative
|
||||
metadata bounds copied at bind time. It does not own amounts, enabled state,
|
||||
reservations, or persistence. `ResourceNode` enter/exit, bind, and transform
|
||||
notifications keep it synchronized with the loaded presentation lifecycle.
|
||||
|
||||
Outside the runtime lifecycle, `simulation/benchmark/` owns reusable,
|
||||
schema-valid workload fixtures. CLI tools and headless scenarios consume those
|
||||
fixtures; production simulation does not depend on benchmark code.
|
||||
@@ -86,9 +94,9 @@ hard to read.
|
||||
| `simulation/state/` | Versioned, serializable mutable records |
|
||||
| `simulation/definitions/` | Stable IDs and immutable gameplay definitions |
|
||||
| `simulation/persistence/` | Validated local save-file storage |
|
||||
| `simulation/benchmark/` | Reproducible full-fidelity headless workloads and metrics |
|
||||
| `simulation/benchmark/` | Reproducible simulation and loaded-world query workloads |
|
||||
| `world/` | Loaded-world interaction geometry and presentation adapters |
|
||||
| `world/resource_nodes/` | Finite resource presentation bound by stable ID |
|
||||
| `world/resource_nodes/` | Finite resource presentation and disposable loaded-anchor index |
|
||||
| `world/storage/` | Storage interaction geometry, never stored quantities |
|
||||
| `world/activity/` | Rest/study/patrol interaction sites and capacity facts |
|
||||
| `player/` | Player input, camera, and active NPC presentation |
|
||||
@@ -127,6 +135,10 @@ improving ownership.
|
||||
- Derived population indexes are disposable acceleration structures. NPC
|
||||
records remain authoritative, and rebuilding the view after initialization,
|
||||
restore, or a tick must produce the same decisions and checksum.
|
||||
- The loaded-resource grid is likewise disposable. `ResourceStateRecord`
|
||||
remains authoritative while its scene node is absent; rebuilding or
|
||||
incrementally refreshing the grid must preserve the linear resolver's exact
|
||||
score winner and stable tie order.
|
||||
- Camera-local grass, ambient butterflies, water animation, smoke, and foliage
|
||||
motion are presentation only. Grass consumes bounded real actor transforms;
|
||||
it does not write NPC positions or become persistent state.
|
||||
|
||||
@@ -770,17 +770,21 @@ Completed:
|
||||
cascading homes, bridge, waterfall, terrain-following river, conifer/tree
|
||||
clusters, and ambient butterflies. Roughly 10,400 camera-local grass
|
||||
particles remain short and patchy and bend from real actor transforms.
|
||||
35. Loaded-resource spatial discovery: `ActiveWorldAdapter` now indexes loaded
|
||||
stable-ID resource anchors in a resource-specific horizontal grid. Exact
|
||||
expanding queries preserve current scoring and selected targets while the
|
||||
reviewed 1,800-source case inspects about 4.4 candidates instead of 1,800.
|
||||
|
||||
Next:
|
||||
|
||||
1. Measure and implement a loaded-resource spatial query through
|
||||
`ActiveWorldAdapter` for far-apart Terrain3D-authored finite sources. Keep
|
||||
simulation-owned resource records, stable IDs, current score/reachability,
|
||||
reservations, player parity, and unload/rebind behavior unchanged.
|
||||
2. Sculpt a real Terrain3D river channel and waterfall shelf before adding a
|
||||
1. Sculpt a real Terrain3D river channel and waterfall shelf before adding a
|
||||
broad foliage asset pass. Use Terrain3D particles for nearby grass and
|
||||
intentional instancing for tree/fern/rock masses; add livestock only with a
|
||||
real identity and interaction contract.
|
||||
intentional instancing for tree/fern/rock masses, then rebake and validate
|
||||
the required village/resource routes.
|
||||
2. During that first larger foliage pass, prove a bounded authoring workflow
|
||||
that places intentional stable-ID `ResourceNode` anchors beside decorative
|
||||
Terrain3D instances. Add livestock only with a real identity and interaction
|
||||
contract.
|
||||
|
||||
Do not start with GIS data, a full city, a large asset pack, or more NPC
|
||||
mechanics. The next proof is a beautiful stage for the systems that already
|
||||
|
||||
@@ -474,6 +474,12 @@ keeps identical final checksums after one reusable per-tick population view and
|
||||
improves that case from 65.84 to 85.81 ticks per second. Revisit the target when
|
||||
world presentation or LOD enters the measured workload.
|
||||
|
||||
[Loaded Resource Discovery 01](benchmarks/LOADED_RESOURCE_DISCOVERY_01.md)
|
||||
proves the first real spatial consumer. Exact loaded-anchor resolution remains
|
||||
near four inspected candidates from 18 through 1,800 resources, preserves every
|
||||
linear selected-target checksum, and keeps persistent authority outside the
|
||||
index.
|
||||
|
||||
## Milestone 9 — Player interaction and social agency
|
||||
|
||||
### Learn
|
||||
@@ -873,18 +879,28 @@ The 600-NPC case falls from 15,187.74 to 11,654.10 microseconds per tick, a
|
||||
cost. See
|
||||
[Simulation scaling baseline 02](benchmarks/SIMULATION_SCALING_BASELINE_02.md).
|
||||
|
||||
The immediate next systems slice should now prove spatial discovery for the
|
||||
world vision: index loaded finite `ResourceNode` anchors through
|
||||
`ActiveWorldAdapter` so Terrain3D-authored sources can be placed much farther
|
||||
apart without an all-node scan for every resolution. Preserve stable IDs,
|
||||
current distance/risk/comfort/priority scoring, reachability, reservations,
|
||||
player parity, unload/rebind authority, and exact deterministic outcomes. First
|
||||
measure 18, 180, and 1,800 loaded candidates; do not choose a generic spatial
|
||||
framework or active/abstract LOD mode before that real consumer proves the
|
||||
contract.
|
||||
The first loaded-world spatial consumer is complete. `ActiveWorldAdapter` owns
|
||||
a disposable 24 m horizontal grid of loaded finite `ResourceNode` anchors.
|
||||
`ActionTargetResolver` expands through nearby ranges and stops only when
|
||||
authoritative risk/comfort/priority bounds prove that no farther source can win.
|
||||
Matched 18/180/1,800-source samples preserve every selected-target checksum;
|
||||
the 1,800-source case falls from 6,448.00 to 46.94 microseconds per resolution.
|
||||
Unload/rebind state authority, stable tie order, moved anchors, reservations,
|
||||
player parity, and a deliberately far high-priority winner remain covered. See
|
||||
[Loaded Resource Discovery 01](benchmarks/LOADED_RESOURCE_DISCOVERY_01.md).
|
||||
|
||||
The immediate next slice should pair this systems foundation with the authored
|
||||
world: sculpt the real Terrain3D river channel and waterfall shelf, rebake and
|
||||
validate navigation, then use the first larger foliage/resource pass to prove a
|
||||
bounded stable-ID anchor placement workflow alongside decorative Terrain3D
|
||||
instancing. Do not generalize the resource grid to people/buildings/events or
|
||||
introduce active/abstract LOD before those consumers need it.
|
||||
|
||||
Recently completed:
|
||||
|
||||
- Loaded-resource spatial discovery: a resource-specific active-world grid
|
||||
preserves exact score winners and lifecycle authority while reducing the
|
||||
reviewed 1,800-anchor query from 6.45 ms to 46.94 µs.
|
||||
- Shared population query view: one transient per-tick all/living/starving
|
||||
index replaces repeated scarce-food relationship scans, preserves exact
|
||||
checksums, and improves the reviewed 600-NPC workload by 23.3%.
|
||||
|
||||
+26
-9
@@ -195,8 +195,8 @@ study, and patrol target typed activity sites. The migration is documented in
|
||||
- **Terrain:** Terrain3D 1.0.2 is installed and enabled
|
||||
- **Jajce runtime:** reusable 512 m Terrain3D seed, stable ResourceNode
|
||||
placement, larger citadel/village-center composition, terrain-following river
|
||||
ribbon, reactive camera-local grass, and Terrain3D-derived runtime navigation
|
||||
with collision guardrails
|
||||
ribbon, reactive camera-local grass, exact indexed finite-resource discovery,
|
||||
and Terrain3D-derived runtime navigation with collision guardrails
|
||||
- **Lookdev baseline:** `Jajce Lookdev 01` is captured at
|
||||
`docs/baselines/jajce_lookdev_01.png` with
|
||||
`tools/capture_jajce_lookdev.gd`
|
||||
@@ -330,7 +330,9 @@ than broad resource zones: trees in foliage clusters, berry patches, animal
|
||||
camps, and village stockpiles can be ranked by reachability, distance, safety,
|
||||
profession, and NPC comfort range. The current resolver already combines
|
||||
distance with resource `safety_risk`, `comfort_distance`, and
|
||||
`discovery_priority` metadata.
|
||||
`discovery_priority` metadata. Loaded anchors are indexed by
|
||||
`ActiveWorldAdapter`; exact expanding queries usually inspect only nearby cells
|
||||
but retain far sources whenever their authoritative metadata can still win.
|
||||
|
||||
### Jajce scaffold
|
||||
|
||||
@@ -548,6 +550,7 @@ NpcVisual navigates through the active world
|
||||
│ ├── SimulationClock.gd
|
||||
│ ├── SimulationManager.gd
|
||||
│ ├── actions/ Selection, execution, and target resolution
|
||||
│ ├── benchmark/ Population/history and resource-query workloads
|
||||
│ ├── definitions/ Stable IDs and custom definition resources
|
||||
│ ├── economy/ Inventory and storage transactions
|
||||
│ ├── events/ Ordered event history and queries
|
||||
@@ -566,6 +569,7 @@ NpcVisual navigates through the active world
|
||||
│ ├── jajce_world_scaffold_test.gd
|
||||
│ ├── knowledge_retention_consequence_test.gd
|
||||
│ ├── jajce_runtime_integration_test.gd
|
||||
│ ├── loaded_resource_spatial_query_test.gd
|
||||
│ ├── npc_visual_lifecycle_test.gd
|
||||
│ ├── opportunity_communication_helper_test.gd
|
||||
│ ├── relationship_consequence_test.gd
|
||||
@@ -577,6 +581,7 @@ NpcVisual navigates through the active world
|
||||
│ └── witnessed_knowledge_consequence_test.gd
|
||||
├── terrain/jajce/ Dedicated Terrain3D seed data and assets
|
||||
├── tools/
|
||||
│ ├── benchmark_loaded_resource_discovery.gd
|
||||
│ └── generate_jajce_terrain_seed.gd
|
||||
├── world/
|
||||
│ ├── jajce/
|
||||
@@ -586,6 +591,7 @@ NpcVisual navigates through the active world
|
||||
│ │ ├── beauty_camera.gd
|
||||
│ │ └── vfx/WindGustField.tscn
|
||||
│ ├── resource_nodes/
|
||||
│ │ ├── LoadedResourceSpatialIndex.gd
|
||||
│ │ ├── ResourceNode.gd
|
||||
│ │ ├── ResourceNode.gd.uid
|
||||
│ │ └── ResourceNode.tscn
|
||||
@@ -643,7 +649,9 @@ These are expected prototype constraints, not necessarily isolated bugs:
|
||||
- Active navigation is used as if all agents are local; no simulation LOD exists.
|
||||
- Unloaded traveling NPCs preserve their state but do not yet advance through
|
||||
abstract travel time.
|
||||
- There is no spatial query/index layer for large populations.
|
||||
- Loaded finite-resource anchors have one measured active-world spatial index;
|
||||
people, buildings, events, and unloaded simulation still have no spatial/LOD
|
||||
layer.
|
||||
- SimulationManager still coordinates the tick lifecycle and bounded
|
||||
player-facing commands, while action rules, active-world queries, economic
|
||||
transactions, and event history have focused collaborators.
|
||||
@@ -962,11 +970,20 @@ reference target, while exposing superlinear population cost and rapid
|
||||
objective-log growth. Workload details and raw samples live in
|
||||
[`docs/benchmarks/`](benchmarks/SIMULATION_SCALING_BASELINE_01.md).
|
||||
|
||||
The next slice should build one stable per-tick population view for the
|
||||
existing trusted-starving-subject query, which currently rebuilds an all-NPC
|
||||
map for each applicable scarce-food decision. Preserve exact selection and
|
||||
continuation checksums, rerun the same benchmark, and use the remaining measured
|
||||
cost before committing to spatial partitions or active/abstract LOD.
|
||||
The first two measured optimizations are complete. A disposable per-tick
|
||||
population view preserves continuation checksums and improves the 600-NPC
|
||||
fixture by 23.3%. A separate resource-specific grid inside
|
||||
`ActiveWorldAdapter` preserves exact selected targets while reducing the
|
||||
reviewed 1,800-loaded-anchor resolution from 6,448.00 to 46.94 microseconds.
|
||||
Raw samples and workload exclusions live in
|
||||
[Simulation scaling baseline 02](benchmarks/SIMULATION_SCALING_BASELINE_02.md)
|
||||
and [Loaded Resource Discovery 01](benchmarks/LOADED_RESOURCE_DISCOVERY_01.md).
|
||||
|
||||
The next slice should return to the authored Jajce stage: sculpt the real
|
||||
Terrain3D river channel and waterfall shelf, rebake/validate navigation, and
|
||||
use the following foliage expansion to prove a bounded stable-ID resource
|
||||
anchor placement workflow beside decorative Terrain3D instances. Do not yet
|
||||
generalize the resource grid or introduce active/abstract simulation LOD.
|
||||
|
||||
The remaining simulation-garden target still aims for:
|
||||
|
||||
|
||||
@@ -551,11 +551,21 @@ profession, and NPC comfort range. The first scoring pass stores
|
||||
`safety_risk`, `comfort_distance`, and `discovery_priority` on resource state
|
||||
and uses them when selecting NPC resource targets.
|
||||
|
||||
The first validated spread contains twelve finite resources: berry bushes and
|
||||
patches, animal camps, trees, and one village woodpile. Placement is guarded by
|
||||
headless tests for stable IDs, food/wood coverage, semantic contexts,
|
||||
discovery metadata, navigation reachability, and non-overlapping pantry/player
|
||||
interaction range.
|
||||
The current validated spread contains eighteen finite resources: berry bushes
|
||||
and patches, animal camps, farm crops, trees, and village/mill woodpiles.
|
||||
Placement is guarded by headless tests for stable IDs, food/wood coverage,
|
||||
semantic contexts, discovery metadata, navigation reachability, and
|
||||
non-overlapping pantry/player interaction range.
|
||||
|
||||
Loaded discovery now goes through a resource-specific horizontal grid owned by
|
||||
`ActiveWorldAdapter`. Queries expand from nearby cells until authoritative
|
||||
resource metadata proves that no farther source can beat the current scored
|
||||
winner. The index preserves stable registration-order ties and contains no
|
||||
amount, reservation, or save authority. ResourceNode unload removes only the
|
||||
loaded anchor; rebinding the same ID restores its indexed position against the
|
||||
existing `ResourceStateRecord`. The reviewed 18/180/1,800-source benchmark and
|
||||
exact-selection contract live in
|
||||
[Loaded Resource Discovery 01](benchmarks/LOADED_RESOURCE_DISCOVERY_01.md).
|
||||
|
||||
## Test scenarios
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# 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
|
||||
```
|
||||
@@ -16,6 +16,14 @@ The default report is written under `user://`. Pass
|
||||
`-- --host-label="<hardware>" --output=res://docs/benchmarks/<name>.json` only
|
||||
when intentionally capturing a reviewed project baseline.
|
||||
|
||||
Loaded-resource discovery has its own bounded runner:
|
||||
|
||||
```bash
|
||||
/Applications/Godot.app/Contents/MacOS/Godot \
|
||||
--headless --path "$PWD" \
|
||||
--script res://tools/benchmark_loaded_resource_discovery.gd
|
||||
```
|
||||
|
||||
Reviewed captures:
|
||||
|
||||
- [Simulation scaling baseline 01](SIMULATION_SCALING_BASELINE_01.md) records
|
||||
@@ -24,3 +32,6 @@ Reviewed captures:
|
||||
- [Simulation scaling baseline 02](SIMULATION_SCALING_BASELINE_02.md) records
|
||||
checksum-identical results after the shared per-tick population view: the
|
||||
600-NPC case is 23.3% faster, while small fixtures expose its fixed cost.
|
||||
- [Loaded Resource Discovery 01](LOADED_RESOURCE_DISCOVERY_01.md) compares the
|
||||
former all-node scan with the exact resource-anchor grid at 18, 180, and
|
||||
1,800 loaded sources.
|
||||
|
||||
@@ -47,12 +47,11 @@ Keep the population view. It has a real relationship/action consumer, improves
|
||||
the measured pressure point, and preserves exact state. Do not add batching or
|
||||
active/abstract NPC modes merely to improve this data-only number.
|
||||
|
||||
The next bounded scale slice should support the world vision directly: a
|
||||
loaded-resource spatial query owned by `ActiveWorldAdapter`. It should let
|
||||
villagers discover finite, stable-ID `ResourceNode` anchors placed much farther
|
||||
apart across Terrain3D while preserving the current score, reachability,
|
||||
reservation, and save/rebind contracts. A benchmark should compare 18, 180,
|
||||
and 1,800 loaded candidates before choosing a grid, tree, or other index.
|
||||
That next bounded scale slice is now complete. The measured workload justified
|
||||
a resource-specific horizontal grid owned by `ActiveWorldAdapter`; exact
|
||||
expanding queries preserve every linear selected-target checksum and reduce the
|
||||
1,800-anchor case from 6,448.00 to 46.94 microseconds. See
|
||||
[Loaded Resource Discovery 01](LOADED_RESOURCE_DISCOVERY_01.md).
|
||||
|
||||
Terrain3D-instanced visual trees and grass are not automatically authoritative
|
||||
resources. Intentional harvest anchors must continue to bind simulation-owned
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"benchmark_seed": 17331,
|
||||
"cases": [
|
||||
{
|
||||
"inspected_reduction_percent": 79.4166666666667,
|
||||
"linear": {
|
||||
"candidates_inspected_average": 18.0,
|
||||
"elapsed_usec_median": 26016,
|
||||
"elapsed_usec_samples": [
|
||||
25865,
|
||||
25941,
|
||||
25967,
|
||||
26016,
|
||||
26055,
|
||||
26153,
|
||||
26498
|
||||
],
|
||||
"queries_per_second_median": 15375.1537515375,
|
||||
"selected_checksum": "6c417e0e25360aa1d2bcba407d3cba5aafe367a2706b93fb0ca631c7bcdb6800",
|
||||
"usec_per_query_median": 65.04
|
||||
},
|
||||
"query_count": 400,
|
||||
"resource_count": 18,
|
||||
"sample_count": 7,
|
||||
"schema_version": 1,
|
||||
"spatial": {
|
||||
"candidates_inspected_average": 3.705,
|
||||
"elapsed_usec_median": 13304,
|
||||
"elapsed_usec_samples": [
|
||||
12896,
|
||||
13249,
|
||||
13300,
|
||||
13304,
|
||||
13428,
|
||||
13465,
|
||||
13580
|
||||
],
|
||||
"queries_per_second_median": 30066.1455201443,
|
||||
"selected_checksum": "6c417e0e25360aa1d2bcba407d3cba5aafe367a2706b93fb0ca631c7bcdb6800",
|
||||
"usec_per_query_median": 33.26
|
||||
},
|
||||
"speedup": 1.95550210463019,
|
||||
"workload_id": "loaded_resource_target_resolution"
|
||||
},
|
||||
{
|
||||
"inspected_reduction_percent": 97.5694444444444,
|
||||
"linear": {
|
||||
"candidates_inspected_average": 180.0,
|
||||
"elapsed_usec_median": 235611,
|
||||
"elapsed_usec_samples": [
|
||||
235062,
|
||||
235300,
|
||||
235372,
|
||||
235611,
|
||||
235870,
|
||||
237526,
|
||||
237936
|
||||
],
|
||||
"queries_per_second_median": 1697.71360420354,
|
||||
"selected_checksum": "2ac9d359d20de54b79d31141abeb59715a94dfb03e21d86aa6fcf6116223a3f6",
|
||||
"usec_per_query_median": 589.0275
|
||||
},
|
||||
"query_count": 400,
|
||||
"resource_count": 180,
|
||||
"sample_count": 7,
|
||||
"schema_version": 1,
|
||||
"spatial": {
|
||||
"candidates_inspected_average": 4.375,
|
||||
"elapsed_usec_median": 15533,
|
||||
"elapsed_usec_samples": [
|
||||
14610,
|
||||
14791,
|
||||
15121,
|
||||
15533,
|
||||
15653,
|
||||
15814,
|
||||
15971
|
||||
],
|
||||
"queries_per_second_median": 25751.6255713642,
|
||||
"selected_checksum": "2ac9d359d20de54b79d31141abeb59715a94dfb03e21d86aa6fcf6116223a3f6",
|
||||
"usec_per_query_median": 38.8325
|
||||
},
|
||||
"speedup": 15.1684156312367,
|
||||
"workload_id": "loaded_resource_target_resolution"
|
||||
},
|
||||
{
|
||||
"inspected_reduction_percent": 99.7530555555556,
|
||||
"linear": {
|
||||
"candidates_inspected_average": 1800.0,
|
||||
"elapsed_usec_median": 2579199,
|
||||
"elapsed_usec_samples": [
|
||||
2573545,
|
||||
2576251,
|
||||
2577722,
|
||||
2579199,
|
||||
2579974,
|
||||
2580177,
|
||||
2581969
|
||||
],
|
||||
"queries_per_second_median": 155.086908765086,
|
||||
"selected_checksum": "67c6bdbb5e371c9e9658808fb215aeeba1f31f71fa731f0b9b1aaae599628013",
|
||||
"usec_per_query_median": 6447.9975
|
||||
},
|
||||
"query_count": 400,
|
||||
"resource_count": 1800,
|
||||
"sample_count": 7,
|
||||
"schema_version": 1,
|
||||
"spatial": {
|
||||
"candidates_inspected_average": 4.445,
|
||||
"elapsed_usec_median": 18775,
|
||||
"elapsed_usec_samples": [
|
||||
18226,
|
||||
18389,
|
||||
18653,
|
||||
18775,
|
||||
18903,
|
||||
19067,
|
||||
19130
|
||||
],
|
||||
"queries_per_second_median": 21304.9267643142,
|
||||
"selected_checksum": "67c6bdbb5e371c9e9658808fb215aeeba1f31f71fa731f0b9b1aaae599628013",
|
||||
"usec_per_query_median": 46.9375
|
||||
},
|
||||
"speedup": 137.374114513981,
|
||||
"workload_id": "loaded_resource_target_resolution"
|
||||
}
|
||||
],
|
||||
"exclusions": [
|
||||
"fixture_construction",
|
||||
"simulation_tick",
|
||||
"serialization",
|
||||
"rendering",
|
||||
"navigation_pathfinding"
|
||||
],
|
||||
"godot_version": "4.7-stable (official)",
|
||||
"host_label": "Apple_M1_Max_64_GB",
|
||||
"inclusions": [
|
||||
"loaded_resource_candidate_discovery",
|
||||
"authoritative_availability_and_scoring",
|
||||
"reservation_and_release"
|
||||
],
|
||||
"resource_counts": [
|
||||
18,
|
||||
180,
|
||||
1800
|
||||
],
|
||||
"resource_spacing": 20.0,
|
||||
"schema_version": 1,
|
||||
"workload_id": "loaded_resource_target_resolution"
|
||||
}
|
||||
Reference in New Issue
Block a user