204 lines
7.8 KiB
GDScript
204 lines
7.8 KiB
GDScript
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)
|