extends SceneTree const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd") var checks := 0 var failures := 0 func _initialize() -> void: call_deferred("run") func expect(ok: bool, message: String) -> void: checks += 1 if not ok: failures += 1 push_error(message) func run() -> void: root.gui_embed_subwindows = true root.size = Vector2i(1280,720) var runtime: Variant = root.get_node("SimulationRuntime") var clock: Variant = root.get_node("GameClock") clock.reset(1,6,0) root.get_node("GameState").reset() runtime.initialize(clock,root.get_node("GameState"),424242) clock.set_paused(true) runtime.configure_save_policy({&"enabled": false}) var main: Control = load("res://scenes/main/main.tscn").instantiate() root.add_child(main) await process_frame runtime.configure_save_policy({&"enabled": false}) for initial: GuestRuntime in runtime.guest_service.get_guests(): initial.state = GuestRuntime.State.LEAVING runtime.guest_service.despawn_guest(initial.guest_id,clock.absolute_minute) main.guest_count_label.pressed.emit() await process_frame var panel: GuestObservationPanel = main.guest_observer.find_child("GuestObservationPanel", true, false) expect(main.guest_observer.visible and panel.guests.disabled, "HUD opens an empty observer without inventing visitors") var service: GuestService = runtime.guest_service var definition: GuestDefinition = service.get_definitions()[0] var guest := service.spawn_guest(&"observer_guest", definition.guest_type_id, clock.absolute_minute, {&"wallet_gold": 500, &"needs": {&"hunger": 90, &"sleep": 70}, &"planned_exit_at": clock.absolute_minute+1000}) panel.refresh() expect(panel.selected_guest_id == guest.guest_id and not panel.guests.disabled, "new real visitor appears in the observer") expect(panel.bars[&"hunger"].value == 90 and "食欲" in panel.priority_label.text, "bars and highest need match actual state") var before := SimulationDigest.compute(runtime.create_snapshot()) for frame: int in 3: panel.refresh() expect(before == SimulationDigest.compute(runtime.create_snapshot()), "observing never changes the simulation") guest.needs[&"sleep"] = 100 panel.refresh() expect(panel.bars[&"sleep"].value == 100 and "睡眠欲" in panel.priority_label.text, "observer refreshes after needs change") for state: int in GuestRuntime.State.values(): guest.state = state panel.refresh() expect(not panel.details.text.is_empty(), "every real state has a label") guest.state = GuestRuntime.State.DECIDING var saved := service.create_snapshot() service.begin_leaving(guest.guest_id,clock.absolute_minute+1,&"TEST") service.despawn_guest(guest.guest_id,clock.absolute_minute+2) panel.refresh() expect(panel.guests.disabled and panel.selected_guest_id.is_empty(), "despawn removes stale selection") expect(service.restore_snapshot(saved), "guest snapshot restores") panel.refresh() expect(panel.selected_guest_id == &"observer_guest" and panel.bars[&"sleep"].value == 100, "read model follows restored service objects") main.guest_observer.hide() main.guest_count_label.pressed.emit() await process_frame expect(main.guest_observer.visible and clock.paused, "reopening preserves pause state") main._refresh_dashboard() if OS.get_environment("THE_TREE_GUEST_CAPTURE") == "1": await process_frame await RenderingServer.frame_post_draw root.get_texture().get_image().save_png("res://artifacts/guest-ai-2026-09-29/observer.png") 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 await process_frame print("Guest observer: %d checks, %d failures" % [checks, failures]) quit(failures)