feat: index loaded resource discovery

This commit is contained in:
Rijad Zuzo
2026-07-17 00:34:30 +02:00
parent 2c88ed6ea8
commit 5356c34fd7
21 changed files with 1392 additions and 69 deletions
+203
View File
@@ -0,0 +1,203 @@
extends SceneTree
const BenchmarkScript := preload("res://simulation/benchmark/LoadedResourceDiscoveryBenchmark.gd")
var failures: Array[String] = []
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
var benchmark := BenchmarkScript.new()
var fixture := benchmark.create_fixture(root, 180, 17331)
_test_exact_bounded_discovery(benchmark, fixture)
_test_far_priority_is_not_pruned(benchmark, fixture)
await _test_unload_rebind_and_movement(fixture)
benchmark.free_fixture(fixture)
var tie_fixture := benchmark.create_fixture(root, 2, 17331)
await _test_stable_tie_order(benchmark, tie_fixture)
benchmark.free_fixture(tie_fixture)
_check(
ResourceNode.get_all().is_empty(), "Fixture cleanup should clear the loaded-node registry"
)
if failures.is_empty():
print("[TEST] Loaded-resource spatial query passed: exact scoring -> lifecycle-safe index")
quit(0)
return
for failure in failures:
push_error("[TEST] " + failure)
quit(1)
func _test_exact_bounded_discovery(benchmark: RefCounted, fixture: Dictionary) -> void:
var comparison: Dictionary = benchmark.measure_fixture(fixture, 64, 2, true)
_check(not comparison.is_empty(), "Linear and spatial target resolution should both complete")
if comparison.is_empty():
return
var linear: Dictionary = comparison["linear"]
var spatial: Dictionary = comparison.get("spatial", {})
_check(not spatial.is_empty(), "The active-world adapter should expose a spatial query")
if spatial.is_empty():
return
_check(
linear["selected_checksum"] == spatial["selected_checksum"],
"Spatial queries should preserve every selected target from the linear reference",
)
_check(
float(spatial["candidates_inspected_average"]) < 12.0,
"Ordinary local queries should inspect a bounded subset of 180 loaded resources",
)
var adapter: ActiveWorldAdapter = fixture["adapter"]
var stats := adapter.get_resource_index_stats()
_check(
int(stats["candidate_count"]) == 180 and int(stats["occupied_cell_count"]) > 1,
"The adapter should index every loaded anchor across multiple horizontal cells",
)
func _test_far_priority_is_not_pruned(benchmark: RefCounted, fixture: Dictionary) -> void:
var adapter: ActiveWorldAdapter = fixture["adapter"]
var manager: Node = fixture["manager"]
var npc: SimNPC = fixture["npc"]
var far_node := ResourceNode.get_by_id(&"benchmark_resource_0179")
var far_state: ResourceStateRecord = manager.get_resource_state(far_node.node_id)
var original_priority := far_state.get_discovery_priority()
far_state.data["discovery_priority"] = 5000.0
adapter.register_resource_node(far_node, far_state)
var linear_adapter: Node = benchmark.create_linear_adapter()
(fixture["root"] as Node).add_child(linear_adapter)
var origin := ResourceNode.get_by_id(&"benchmark_resource_0001").global_position
var linear_result: Dictionary = manager.target_resolver.resolve(
npc, origin, manager, linear_adapter
)
manager.release_resource(StringName(linear_result.get("target_id", "")), npc.id)
var spatial_result: Dictionary = manager.target_resolver.resolve(npc, origin, manager, adapter)
manager.release_resource(StringName(spatial_result.get("target_id", "")), npc.id)
_check(
(
not linear_result.is_empty()
and linear_result["target_id"] == spatial_result.get("target_id", "")
and StringName(spatial_result["target_id"]) == far_node.node_id
),
"Metadata bounds should retain a far source that legitimately wins exact scoring",
)
_check(
int(manager.target_resolver.last_resource_query_stats["range_pass_count"]) > 1,
"A winning far source should make the query expand beyond its first local cell range",
)
far_state.data["discovery_priority"] = original_priority
adapter.register_resource_node(far_node, far_state)
func _test_unload_rebind_and_movement(fixture: Dictionary) -> void:
var adapter: ActiveWorldAdapter = fixture["adapter"]
var manager: Node = fixture["manager"]
var resource_root: Node3D = fixture["resource_root"]
var original := ResourceNode.get_by_id(&"benchmark_resource_0001")
var original_position := original.global_position
var state: ResourceStateRecord = manager.get_resource_state(original.node_id)
state.set_amount_remaining(77.0)
original.free()
_check(
int(adapter.get_resource_index_stats()["candidate_count"]) == 179,
"Unloading a ResourceNode should remove only its presentation anchor from the index",
)
_check(
(
manager.get_resource_state(&"benchmark_resource_0001") == state
and is_equal_approx(state.get_amount_remaining(), 77.0)
),
"Unloading an anchor should preserve authoritative resource state",
)
var replacement := ResourceNode.new()
replacement.name = "ReboundResource"
replacement.node_id = &"benchmark_resource_0001"
replacement.action_id = state.get_action_id()
replacement.resource_id = state.get_resource_id()
replacement.initial_amount = 100000.0
replacement.safety_risk = state.get_safety_risk()
replacement.comfort_distance = state.get_comfort_distance()
replacement.discovery_priority = state.get_discovery_priority()
replacement.debug_label_enabled = false
replacement.position = original_position + Vector3(60.0, 0.0, 40.0)
var interaction_point := Marker3D.new()
interaction_point.name = "InteractionPoint"
replacement.add_child(interaction_point)
resource_root.add_child(replacement)
_check(
(
replacement.state == state
and is_equal_approx(replacement.get_amount_remaining(), 77.0)
and int(adapter.get_resource_index_stats()["candidate_count"]) == 180
),
"Rebinding the stable ID should restore its indexed anchor without replacing state",
)
var rebound_candidates := adapter.get_resource_candidates_in_radius(
state.get_action_id(), replacement.global_position, 0.1
)
_check(
(
rebound_candidates.size() == 1
and StringName(rebound_candidates[0]["target_id"]) == replacement.node_id
),
"The rebound anchor should be discoverable at its new Terrain3D-authored position",
)
replacement.position += Vector3(48.0, 0.0, -24.0)
await process_frame
var moved_candidates := adapter.get_resource_candidates_in_radius(
state.get_action_id(), replacement.global_position, 0.1
)
_check(
(
moved_candidates.size() == 1
and StringName(moved_candidates[0]["target_id"]) == replacement.node_id
),
"Moving a loaded anchor should refresh its spatial cell before the next query frame",
)
func _test_stable_tie_order(benchmark: RefCounted, fixture: Dictionary) -> void:
var adapter: ActiveWorldAdapter = fixture["adapter"]
var manager: Node = fixture["manager"]
var npc: SimNPC = fixture["npc"]
var first := ResourceNode.get_by_id(&"benchmark_resource_0000")
var second := ResourceNode.get_by_id(&"benchmark_resource_0001")
first.position = Vector3(-10.0, 0.0, 0.0)
second.position = Vector3(10.0, 0.0, 0.0)
for node in [first, second]:
var state: ResourceStateRecord = manager.get_resource_state(node.node_id)
state.set_enabled(true)
state.data["safety_risk"] = 0.0
state.data["comfort_distance"] = 18.0
state.data["discovery_priority"] = 0.0
adapter.register_resource_node(node, state)
await process_frame
var linear_adapter: Node = benchmark.create_linear_adapter()
(fixture["root"] as Node).add_child(linear_adapter)
var linear_result: Dictionary = manager.target_resolver.resolve(
npc, Vector3.ZERO, manager, linear_adapter
)
manager.release_resource(StringName(linear_result.get("target_id", "")), npc.id)
var spatial_result: Dictionary = manager.target_resolver.resolve(
npc, Vector3.ZERO, manager, adapter
)
manager.release_resource(StringName(spatial_result.get("target_id", "")), npc.id)
_check(
(
StringName(linear_result.get("target_id", "")) == first.node_id
and spatial_result.get("target_id", "") == linear_result.get("target_id", "")
),
"Equal resource scores should preserve the former first-loaded stable tie winner",
)
func _check(condition: bool, message: String) -> void:
if not condition:
failures.append(message)
@@ -0,0 +1 @@
uid://7yplcc3s2oks