extends SceneTree const SHARED_RESOURCE_ID := &"shared_berry" const SHARED_STORAGE_ID := &"shared_pantry" const SHARED_ACTIVITY_ID := &"shared_bench" const SHARED_ANIMAL_ID := &"shared_goat" var failures: Array[String] = [] func _initialize() -> void: call_deferred("_run") func _run() -> void: var first := _create_context(&"context_one", &"world_one", &"location_one", Vector3.ZERO) var second := _create_context( &"context_two", &"world_two", &"location_two", Vector3(1000.0, 0.0, 0.0) ) root.add_child(first["root"]) root.add_child(second["root"]) await process_frame _test_context_identity_and_duplicate_local_ids(first, second) _test_context_scoped_queries(first, second) _test_activity_interaction_range(first) _test_cross_kind_uniqueness(first) await _test_unregister_rebind_and_generation(first) (first["root"] as Node).free() (second["root"] as Node).free() _check( ResourceNode.get_all().is_empty(), "Context cleanup should release legacy resource views" ) _check(StorageNode.get_all().is_empty(), "Context cleanup should release legacy storage views") _check( ActivitySite.get_all().is_empty(), "Context cleanup should release legacy activity views" ) _check(AnimalNode.get_all().is_empty(), "Context cleanup should release legacy animal views") _finish() func _test_context_identity_and_duplicate_local_ids(first: Dictionary, second: Dictionary) -> void: var first_adapter := first["adapter"] as ActiveWorldAdapter var second_adapter := second["adapter"] as ActiveWorldAdapter _check( ( first_adapter.get_context_identity() == { "context_id": &"context_one", "world_id": &"world_one", "location_id": &"location_one", } ), "Each adapter should expose its explicit context/world/location identity", ) _check( first_adapter.get_target_registry().size() == 4, "The first context should register all four canonical target kinds", ) _check( second_adapter.get_target_registry().size() == 4, "A second context may reuse every local target ID without a collision", ) for target_id in [SHARED_RESOURCE_ID, SHARED_STORAGE_ID, SHARED_ACTIVITY_ID, SHARED_ANIMAL_ID]: var first_provider := first_adapter.get_target_provider(target_id) var second_provider := second_adapter.get_target_provider(target_id) _check( ( first_provider != null and second_provider != null and first_provider != second_provider ), "Canonical lookup for '%s' should resolve only the owning context" % target_id, ) _check( ( first_adapter.resolve_target_handle( second_adapter.get_target_handle(SHARED_RESOURCE_ID) ) == null ), "Transient handles from another adapter must not resolve", ) func _test_context_scoped_queries(first: Dictionary, second: Dictionary) -> void: var first_adapter := first["adapter"] as ActiveWorldAdapter var second_adapter := second["adapter"] as ActiveWorldAdapter var first_resource := first["resource"] as ResourceNode var second_resource := second["resource"] as ResourceNode var first_candidates := first_adapter.get_resource_candidates_in_radius( SimulationIds.ACTION_GATHER_FOOD, first_resource.global_position, 2.0 ) var second_candidates := second_adapter.get_resource_candidates_in_radius( SimulationIds.ACTION_GATHER_FOOD, second_resource.global_position, 2.0 ) _check( first_candidates.size() == 1 and second_candidates.size() == 1, "Each spatial index should return its own same-ID resource", ) _check( ( first_adapter . get_resource_candidates_in_radius( SimulationIds.ACTION_GATHER_FOOD, second_resource.global_position, 2.0 ) . is_empty() ), "Equal local target IDs must not leak through another context's spatial query", ) _check( first_adapter.get_activity_candidates(SimulationIds.ACTION_REST).size() == 1, "Activity queries should read the context registry", ) _check( ( first_adapter.get_storage_target(SHARED_STORAGE_ID)["position"] != second_adapter.get_storage_target(SHARED_STORAGE_ID)["position"] ), "Storage lookup should return the owning context's position", ) _check( first_adapter.get_animal_candidates(SimulationIds.ACTION_FEED_ANIMAL).size() == 1, "Animal queries should read the context registry", ) _check( ( first_adapter . get_animal_nodes_in_radius((second["animal"] as AnimalNode).global_position, 2.0) . is_empty() ), "Animal radius queries must not return another context's same-ID provider", ) func _test_cross_kind_uniqueness(fixture: Dictionary) -> void: var adapter := fixture["adapter"] as ActiveWorldAdapter var conflicting := ActivitySite.new() conflicting.site_id = SHARED_RESOURCE_ID conflicting.action_id = SimulationIds.ACTION_REST conflicting.display_name = "Conflicting bench" conflicting.debug_label_enabled = false var interaction_point := Marker3D.new() interaction_point.name = "InteractionPoint" conflicting.add_child(interaction_point) (fixture["root"] as Node).add_child(conflicting) _check( adapter.get_target_registry().size() == 4, "A same-context cross-kind collision must not replace or add a canonical target", ) _check( ( adapter.get_target_registry().get_descriptor(SHARED_RESOURCE_ID).get_target_kind() == &"resource" ), "The original target kind should survive a cross-kind registration attempt", ) conflicting.free() func _test_activity_interaction_range(fixture: Dictionary) -> void: var adapter := fixture["adapter"] as ActiveWorldAdapter var descriptor := adapter.get_target_registry().get_descriptor(SHARED_ACTIVITY_ID) var capability := descriptor.get_capability(SimulationIds.ACTION_REST) var interaction_range := float(capability.get_attribute(&"interaction_range", -1.0)) _check( is_finite(interaction_range) and interaction_range > 0.0, "Activity capabilities should expose a positive finite generic interaction range", ) var invalid := ActivitySite.new() invalid.interaction_range = 0.0 _check( not invalid.is_interaction_range_valid(), "ActivitySite should reject a non-positive interaction range", ) invalid.interaction_range = NAN _check( not invalid.is_interaction_range_valid(), "ActivitySite should reject a non-finite interaction range", ) invalid.free() func _test_unregister_rebind_and_generation(fixture: Dictionary) -> void: var adapter := fixture["adapter"] as ActiveWorldAdapter var first_resource := fixture["resource"] as ResourceNode var first_handle := adapter.get_target_handle(SHARED_RESOURCE_ID) var previous_position := first_resource.global_position first_resource.free() _check( not adapter.get_target_registry().is_handle_valid(first_handle), "Unloading the provider should invalidate its transient handle", ) _check( int(adapter.get_resource_index_stats()["candidate_count"]) == 0, "Unloading the provider should remove it from the context spatial index", ) var replacement := _create_resource( SHARED_RESOURCE_ID, previous_position + Vector3(8.0, 0.0, 0.0) ) (fixture["root"] as Node).add_child(replacement) await process_frame var rebound_handle := adapter.get_target_handle(SHARED_RESOURCE_ID) _check( rebound_handle != null and rebound_handle.get_generation() > first_handle.get_generation(), "Rebinding the same local ID should advance its generation", ) _check( adapter.get_target_provider(SHARED_RESOURCE_ID, &"resource") == replacement, "Rebinding should point canonical lookup at the replacement provider", ) _check( ( ( adapter . get_resource_candidates_in_radius( SimulationIds.ACTION_GATHER_FOOD, replacement.global_position, 0.1 ) . size() ) == 1 ), "A rebound resource should be indexed at its new position", ) func _create_context( context_id: StringName, world_id: StringName, location_id: StringName, offset: Vector3 ) -> Dictionary: var context_root := Node3D.new() context_root.name = String(context_id) context_root.position = offset var adapter := ActiveWorldAdapter.new() adapter.name = "ActiveWorldAdapter" adapter.context_id = context_id adapter.world_id = world_id adapter.location_id = location_id context_root.add_child(adapter) var resource := _create_resource(SHARED_RESOURCE_ID, Vector3(1.0, 0.0, 0.0)) context_root.add_child(resource) var storage := _create_storage(SHARED_STORAGE_ID, Vector3(2.0, 0.0, 0.0)) context_root.add_child(storage) var activity := _create_activity(SHARED_ACTIVITY_ID, Vector3(3.0, 0.0, 0.0)) context_root.add_child(activity) var animal := _create_animal(SHARED_ANIMAL_ID, Vector3(4.0, 0.0, 0.0)) context_root.add_child(animal) return { "root": context_root, "adapter": adapter, "resource": resource, "storage": storage, "activity": activity, "animal": animal, } func _create_resource(target_id: StringName, position: Vector3) -> ResourceNode: var node := ResourceNode.new() node.node_id = target_id node.action_id = SimulationIds.ACTION_GATHER_FOOD node.resource_id = SimulationIds.RESOURCE_FOOD node.debug_label_enabled = false node.position = position var interaction_point := Marker3D.new() interaction_point.name = "InteractionPoint" node.add_child(interaction_point) return node func _create_storage(target_id: StringName, position: Vector3) -> StorageNode: var node := StorageNode.new() node.storage_id = target_id node.accepted_items = [SimulationIds.RESOURCE_FOOD] node.debug_label_enabled = false node.position = position var interaction_point := Marker3D.new() interaction_point.name = "InteractionPoint" node.add_child(interaction_point) return node func _create_activity(target_id: StringName, position: Vector3) -> ActivitySite: var node := ActivitySite.new() node.site_id = target_id node.action_id = SimulationIds.ACTION_REST node.debug_label_enabled = false node.position = position var interaction_point := Marker3D.new() interaction_point.name = "InteractionPoint" node.add_child(interaction_point) return node func _create_animal(target_id: StringName, position: Vector3) -> AnimalNode: var node := AnimalNode.new() node.animal_id = target_id node.animal_definition_id = &"domestic_goat" node.debug_label_enabled = false node.position = position var interaction_point := Marker3D.new() interaction_point.name = "InteractionPoint" node.add_child(interaction_point) return node func _check(condition: bool, message: String) -> void: if not condition: failures.append(message) func _finish() -> void: if failures.is_empty(): print("[TEST] Context-scoped world targets passed: four kinds, isolation, lifecycle") quit(0) return for failure in failures: push_error("[TEST] " + failure) quit(1)