extends SceneTree const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd") const LegacyType := preload("res://scripts/world/legacy_stair_service.gd") class LegacyViewRuntime extends RefCounted: var world_service := WorldService.new() var path_service := PathService.new() var legacy_stairs := LegacyType.new() class WaitStatisticsRuntime extends RefCounted: var samples := 0 func get_elevator_wait_statistics(_shaft_id: StringName) -> Dictionary: return {&"sample_count":samples, &"mean_wait_minutes":2.5, &"p95_wait_minutes":7, &"oldest_wait_minutes":9, &"window_minutes":60, &"event_history_limit":256} var _checks := 0 var _failures := 0 var _main: Control var _runtime: Variant var _clock: Variant var _preview: WorldPreview var _guest_stairs: StringName = &"" var _service_stairs: StringName = &"" var _elevator: StringName = &"" func _initialize() -> void: call_deferred("_run") func _run() -> void: _clock = root.get_node("GameClock") _runtime = root.get_node("SimulationRuntime") var state: Variant = root.get_node("GameState") _clock.reset(1,6,0) state.reset() _expect(_runtime.initialize(_clock,state,947263)[&"valid"], "normal Runtime initializes the transport UI fixture") _clock.set_paused(true) root.size = Vector2i(1280,720) _main = load("res://scenes/main/main.tscn").instantiate() as Control root.add_child(_main) _runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false}) _preview = _main.get("world_preview") await process_frame await process_frame var buttons: Dictionary = _main.get("build_buttons") _expect(buttons.has(&"guest_stairs") and buttons.has(&"service_stairs"), "both registered stair definitions appear in the building palette") _expect("客用階段" in buttons[&"guest_stairs"].text and "業務用階段" in buttons[&"service_stairs"].text, "stairs use the localized catalog names") var icon := buttons[&"guest_stairs"].icon as AtlasTexture _expect(icon != null and icon.atlas == _preview.visual_theme.pixel_dungeon_tiles and icon.region == Rect2(48,48,16,16), "stair controls reuse the existing real Kenney Tiny Dungeon stair tile") _main.call("_select_build_definition", &"guest_stairs") _main.call("_on_map_cell_clicked", Vector3i(-1,1,0)) _main.call("_set_layer", 1) _main.call("_select_build_definition", &"service_stairs") _main.call("_on_map_cell_clicked", Vector3i(-1,1,1)) _main.call("_set_layer", 0) _main.call("_select_build_definition", &"guest_elevator") _main.call("_on_map_cell_clicked", Vector3i(0,0,0)) _expect(_runtime.construction_service.get_jobs().size() == 3, "normal palette and map clicks pay for two stairs and one elevator") _clock.advance_minutes(310) _main.call("_clear_build_selection") for facility: Dictionary in _runtime.construction_service.get_facilities(): match facility[&"definition_id"]: &"guest_stairs": _guest_stairs = facility[&"instance_id"] &"service_stairs": _service_stairs = facility[&"instance_id"] &"guest_elevator": _elevator = facility[&"instance_id"] _expect(not _guest_stairs.is_empty() and not _service_stairs.is_empty() and not _elevator.is_empty(), "all three paid construction projects finish") if _guest_stairs.is_empty() or _service_stairs.is_empty() or _elevator.is_empty(): _finish() return _main.call("_on_facility_selected", _guest_stairs) _expect(_main.get("selected_heading_label").text == "客用階段", "finished route-proxy stairs display an inspector instead of a syncing placeholder") var detail: String = _main.get("selected_detail_label").text _expect("1F ↔ 2F" in detail and "客・従業員用" in detail and "魔力は不要" in detail, "guest stair inspector explains its floors, users and operation") _expect(not _main.get("selected_elevator_controls").visible, "stairs have no cabin stop button") _main.call("_on_facility_selected", _service_stairs) detail = _main.get("selected_detail_label").text _expect(_main.get("selected_heading_label").text == "業務用階段" and "従業員専用" in detail and "BACK" in detail, "service stair inspector identifies staff-only back-layer access") _main.call("_on_facility_selected", _elevator) detail = _main.get("selected_detail_label").text _expect("最近の乗車記録 0人(計測待ち)" in detail and "現在の最長待ち 0分" in detail, "unused real elevator labels the sample as pending instead of an observed zero average") _expect("直近256件" in _main.get("selected_detail_label").tooltip_text and "過去60分" in _main.get("selected_detail_label").tooltip_text, "statistics tooltip explains retained-event sampling") _test_sample_format() await _test_legacy_stair_selection() _main.call("_on_facility_selected", _guest_stairs) _expect(_main.get("selected_detail_label").tooltip_text.is_empty(), "switching from elevator to stairs removes obsolete wait-statistics tooltip") _preview.set_zoom(2.5) _preview.pan_offset += _preview.size*0.5-_preview.cell_to_canvas(Vector3i(0,1,0)) _preview.queue_redraw() await process_frame await process_frame if OS.get_environment("THE_TREE_STAIRS_UI_CAPTURE") == "1": await RenderingServer.frame_post_draw DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path("res://artifacts/transport")) root.get_texture().get_image().save_png("res://artifacts/transport/stairs-inspector.png") _finish() func _test_sample_format() -> void: var fixture := WaitStatisticsRuntime.new() _main.set("_runtime", fixture) var pending: String = _main.call("_elevator_wait_text", &"fixture") _expect("計測待ち" in pending and not "平均待ち" in pending and "9分" in pending, "no boarding samples still show the current live queue age") fixture.samples = 4 var measured: String = _main.call("_elevator_wait_text", &"fixture") _expect("最近の乗車記録 4人" in measured and "平均待ち 2.5分 / 95% 7.0分" in measured, "sampled average and P95 retain precision and correct labels") _expect("現在の最長待ち 9分" in measured and not "直近60分の乗車" in measured, "current queue age stays distinct from the retained boarding sample") _main.set("_runtime", _runtime) func _test_legacy_stair_selection() -> void: var fixture := LegacyViewRuntime.new() fixture.world_service.reset({&"min_x":-2,&"max_x":2,&"min_y":-1,&"max_y":2}) fixture.path_service.rebuild_graph([Vector3i.ZERO,Vector3i(0,1,0),Vector3i(0,0,1),Vector3i(0,1,1)]) _expect(fixture.legacy_stairs.configure(fixture.path_service) and fixture.legacy_stairs.migrate_existing_vertical_walks(), "legacy view uses real canonical stair migration") var before := SimulationDigest.compute(_runtime.create_snapshot()) _preview.set_runtime(fixture) _preview.reset_view() _preview.layer_mode = WorldPreview.LayerMode.FRONT var rect: Rect2 = _preview.call("_legacy_stair_rect", Vector3i(0,1,0)) var stair_id := _preview.legacy_stair_at_canvas(rect.get_center()) _expect(stair_id == &"legacy.stairs:0:0:0", "legacy stairs are hit-tested on the upper landing") var inactive_front: Array = _preview._other_layer_rooms() _expect(inactive_front.size()==1 and inactive_front[0][&"id"]==&"legacy.stairs:1:0:0" and inactive_front[0][&"rect"]==rect, "opposite legacy stairs appear once at their real compact footprint without construction service") _expect(bool(inactive_front[0].get(&"legacy_stair",false)), "legacy ghost uses compact stair art rather than a completed facility room") _expect(_preview.legacy_stair_at_canvas(_preview.get_cell_rect(Vector3i(0,1,0)).position+Vector2.ONE).is_empty(), "small legacy stair target preserves the rest of an existing room's click area") _expect(_preview.legacy_stair_at_canvas(_preview.cell_to_canvas(Vector3i.ZERO)).is_empty(), "lower floor cannot select the stair glyph drawn upstairs") _click(rect.get_center()) _expect(_main.get("_selected_entity_kind") == &"legacy_stairs" and _main.get("_selected_entity_id") == stair_id, "legacy glyph click opens its dedicated selection without clearing its ID") _expect("既設の階段" == _main.get("selected_heading_label").text and "1F ↔ 2F" in _main.get("selected_detail_label").text, "legacy inspector describes the preserved connection") _preview.layer_mode = WorldPreview.LayerMode.BACK var inactive_back: Array = _preview._other_layer_rooms() _expect(inactive_back.size()==1 and inactive_back[0][&"id"]==&"legacy.stairs:0:0:0", "back view exposes front legacy stair without duplicating selected stair") _click(rect.get_center()) _expect(_main.get("_selected_entity_id") == &"legacy.stairs:1:0:0" and "客・従業員用" in _main.get("selected_detail_label").text and "BACK" in _main.get("selected_detail_label").text, "legacy BACK stairs preserve the old public access instead of falsely claiming staff-only access") if OS.get_environment("THE_TREE_LAYER_LEGACY_CAPTURE") == "1": _preview.set_zoom(3.0) _preview.pan_offset += _preview.size*0.5-_preview.cell_to_canvas(Vector3i(0,1,0)) for layer: int in [0,1]: _preview.layer_mode=layer _preview._process(1.0) await process_frame;await process_frame;await RenderingServer.frame_post_draw _expect(root.get_texture().get_image().save_png(ProjectSettings.globalize_path("res://artifacts/facility-dimensions-2026-09-29/layer-legacy-%d.png" % layer))==OK,"capture opposite legacy stairs") var records := _preview.get_legacy_stair_records() records[0][&"id"] = &"changed.view.copy" _expect(not str(fixture.legacy_stairs.create_snapshot()).contains("changed.view.copy"), "visual records cannot mutate saved stair ownership") await process_frame await process_frame _expect(SimulationDigest.compute(_runtime.create_snapshot()) == before, "stair painting, selection and inspection never advance or mutate Runtime") _preview.set_runtime(_runtime) _main.call("_set_layer", 0) func _click(at: Vector2) -> void: var event := InputEventMouseButton.new() event.button_index = MOUSE_BUTTON_LEFT event.pressed = true event.position = at _preview.call("_gui_input",event) func _finish() -> void: _clock.set_paused(true) var _audio_cleanup_final: Dictionary = await FixtureCleanup.free_owner_and_wait(self, _main) if not bool(_audio_cleanup_final.get(&"passed", false)): push_error("Ordinary fixture audio cleanup failed: %s" % str(_audio_cleanup_final)) quit(96) return print("Stair and transport details UI: %d checks, %d failures" % [_checks,_failures]) quit(_failures) func _expect(ok: bool, label: String) -> void: _checks += 1 if not ok: _failures += 1 push_error(label)