extends SceneTree var failures: Array[String] = [] func _initialize() -> void: call_deferred("_run") func _run() -> void: var main_scene: Node = load("res://main.tscn").instantiate() root.add_child(main_scene) await process_frame for _frame in 10: await physics_frame var simulation_manager: Node = main_scene.get_node("SimulationManager") simulation_manager.set_process(false) _check(simulation_manager.npcs.size() == 6, "Baseline should create six NPCs") _check( main_scene.has_node("JajceWorld/TerrainRoot/Terrain3D"), "Playable runtime should instance the Jajce Terrain3D world" ) var terrain: Terrain3D = main_scene.get_node("JajceWorld/TerrainRoot/Terrain3D") _check( terrain.get_camera() == main_scene.get_node("CameraRig/Camera3D"), "Runtime Terrain3D should bind to the gameplay camera" ) var camera_rig := main_scene.get_node("CameraRig") _check( camera_rig.has_method("apply_presentation_preset"), "Runtime camera should expose a presentation staging preset" ) var presentation_focus := Vector3(-2.0, 1.2, -0.5) camera_rig.apply_presentation_preset(presentation_focus, 128.0, 0.95) _check( camera_rig.global_position.distance_to(presentation_focus) > 10.0, "Presentation preset should pull the camera back from the village focus" ) _check(terrain.collision_mode != 0, "Runtime Terrain3D collision should be enabled") _check( not main_scene.has_node("JajceWorld/NavigationRegion3D/GreyboxGround"), "Runtime should not keep the temporary greybox navigation ground" ) _check( ( not main_scene.has_node("World") and not main_scene.has_node("ResourceNodes") and not main_scene.has_node("ActivityMarkers") and not main_scene.has_node("JajceWorld/LegacyActivityMarkers") ), "Runtime should not retain duplicate flat-world objects" ) var resource_root := main_scene.get_node("JajceWorld/WorldObjects/ResourceNodes") _check(resource_root.get_child_count() == 12, "Runtime should contain twelve Jajce ResourceNodes") _check( simulation_manager.resource_states.size() == 12, "Simulation authority should bind all twelve Jajce resources" ) var village_root := main_scene.get_node("JajceWorld/VillageRoot") var path_strips := 0 for child in village_root.get_children(): if child.name.begins_with("Path_"): path_strips += 1 _check(path_strips >= 4, "Runtime should include authored path strips for first-read composition") var navigation_map: RID = main_scene.get_world_3d().navigation_map var navigation_region := main_scene.get_node("JajceWorld/NavigationRegion3D") as NavigationRegion3D _check( navigation_region.navigation_mesh.resource_path == "res://world/jajce/JajceNavigationMesh.tres", "Runtime navigation should use the Terrain3D-derived baked mesh resource" ) await _wait_for_navigation_map(navigation_map) NavigationServer3D.map_force_update(navigation_map) var fixed_origins := [Vector3(-6.0, 0.0, -4.0), Vector3(0.0, 0.0, 0.0), Vector3(6.0, 0.0, 4.0)] var destinations: Array[Vector3] = [] _check( main_scene.has_node("JajceWorld/WorldObjects/StorageSites/VillagePantry"), "Runtime should expose a typed VillagePantry StorageNode" ) _check( not main_scene.has_node("JajceWorld/LegacyActivityMarkers/PantryMarker"), "Runtime should not keep the pantry as a legacy activity marker" ) var pantry := main_scene.get_node("JajceWorld/WorldObjects/StorageSites/VillagePantry") as StorageNode destinations.append(pantry.get_interaction_position()) var activity_root := main_scene.get_node("JajceWorld/WorldObjects/ActivitySites") _check(activity_root.get_child_count() == 3, "Runtime should expose three typed activity sites") for site in activity_root.get_children(): destinations.append((site as ActivitySite).get_interaction_position()) for resource in resource_root.get_children(): destinations.append((resource as ResourceNode).interaction_point.global_position) for origin in fixed_origins: for destination in destinations: var path := NavigationServer3D.map_get_path(navigation_map, origin, destination, true) _check( not path.is_empty(), "Navigation path should exist from %s to %s" % [origin, destination] ) _check_path_tracks_terrain( terrain, path, "Runtime navigation path should track Terrain3D height" ) _check_path_reaches_destination( path, destination, "Runtime navigation path should reach its requested target" ) var village := SimVillage.new() var worker := SimNPC.new(100, "BaselineWorker", SimulationIds.PROFESSION_SCHOLAR, 5.0, 5.0) worker.set_task(SimulationIds.ACTION_STUDY, 2.0) worker.start_working() var executor := ActionExecutionSystem.new() executor.advance_npc(worker, village) executor.advance_npc(worker, village) _check(worker.task_complete, "A two-tick working task should complete") var starving := SimNPC.new(101, "BaselineStarving", SimulationIds.PROFESSION_WANDERER, 5.0, 5.0) starving.hunger = 100.0 starving.starvation_death_threshold = 1 executor.advance_npc(starving, village) _check(starving.is_dead, "Starvation threshold should still kill an NPC") var adapter := main_scene.get_node("ActiveWorldAdapter") as ActiveWorldAdapter var storage_target := adapter.get_activity_target(SimulationIds.ACTION_DEPOSIT_FOOD) _check( storage_target.get("target_id", "") == String(SimulationIds.STORAGE_VILLAGE_PANTRY), "Runtime adapter should route storage actions to village_pantry" ) var study_target := adapter.get_activity_target(SimulationIds.ACTION_STUDY) _check( study_target.get("target_id", "") == "study_desk", "Runtime adapter should route study to the typed study desk" ) if failures.is_empty(): print("[TEST] Jajce runtime passed: 6 NPCs, 12 resources, typed sites") quit(0) return for failure in failures: push_error("[TEST] " + failure) quit(1) func _wait_for_navigation_map(navigation_map: RID) -> void: for attempt in 30: if ( NavigationServer3D.map_get_iteration_id(navigation_map) > 0 and not NavigationServer3D.map_get_regions(navigation_map).is_empty() ): await physics_frame return await physics_frame _check(false, "Navigation map did not synchronize within 30 physics frames") func _check(condition: bool, message: String) -> void: if not condition: failures.append(message) func _check_path_tracks_terrain(terrain: Terrain3D, path: PackedVector3Array, message: String) -> void: if path.is_empty(): return for point in path: var terrain_height: float = terrain.data.get_height(point) if is_nan(terrain_height): failures.append("%s: missing terrain height at %s" % [message, point]) return if absf(point.y - terrain_height) > 0.85: failures.append( "%s: path point %s is too far from terrain height %.2f" % [message, point, terrain_height] ) return func _check_path_reaches_destination(path: PackedVector3Array, destination: Vector3, message: String) -> void: if path.is_empty(): return var final_point := path[path.size() - 1] var final_xz := Vector2(final_point.x, final_point.z) var destination_xz := Vector2(destination.x, destination.z) if final_xz.distance_to(destination_xz) > 1.5: failures.append( "%s: final path point %s is too far from %s" % [message, final_point, destination] )