# system_option_ui_test —— P11 系统设置窗 headless 自检(真 uiscript + 假 audio/cam/env)。 # godot --headless --path project --script system_option_ui_test.gd # 校验 systemoptiondialog.py 装载、音量 / 镜头 / 雾控件绑定(对照 uisystemoption.py)、 # 持久化到 user://system_option.cfg。缺 uiscript 资产时优雅跳过。 extends SceneTree const SystemOptionUI = preload("res://ui/system_option_ui.gd") class FakeAudio extends Node: var master_bgm := 0.6 var master_sfx := 0.9 var _bgm := [null, null] var _bgm_cur := 0 class FakeCam extends Node: var max_dist := 20.0 var dist := 18.0 var _fail := 0 func _ck(c: bool, m: String) -> void: if not c: _fail += 1 printerr("FAIL: " + m) func _init() -> void: _run() if _fail == 0: print("PASS: system_option_ui_test (layout + volume/camera/fog bind + cfg persist)") quit(0) else: printerr("%d check(s) failed" % _fail) quit(1) func _cfg_path() -> String: return ProjectSettings.globalize_path(SystemOptionUI.config_path()) func _run() -> void: var assets := AssetRoot.path() if not FileAccess.file_exists(assets.path_join("uiscript/uiscript/systemoptiondialog.py")): print(" (skip: no systemoptiondialog.py — assets checkout missing)") return # 干净起步 if FileAccess.file_exists(_cfg_path()): DirAccess.remove_absolute(_cfg_path()) var UiManager = load("res://ui/ui_manager.gd") var ui: CanvasLayer = UiManager.new() get_root().add_child(ui) ui._ready() var au := FakeAudio.new() var cam := FakeCam.new() get_root().add_child(au) get_root().add_child(cam) var env := Environment.new() var so: Node = SystemOptionUI.new() get_root().add_child(so) so.setup(ui, assets, au, func(): return cam, func(): return env) so.open() _ck(so.is_open(), "system-option window opened") if not so.is_open(): return # --- 音量 sliderbar → snd.SetMusicVolume / SetSoundVolume --- var mv: Control = so._node("music_volume_controller") var sv: Control = so._node("sound_volume_controller") _ck(mv is Range and sv is Range, "volume controllers are Range sliders") _ck(is_equal_approx(mv.min_value, 0.0) and is_equal_approx(mv.max_value, 1.0), "music slider range set to 0..1") _ck(mv.value_changed.is_connected(so._on_music_volume), "music slider wired to _on_music_volume") _ck(sv.value_changed.is_connected(so._on_sound_volume), "sound slider wired to _on_sound_volume") so._on_music_volume(0.30) # = 拖动 music_volume_controller _ck(is_equal_approx(au.master_bgm, 0.30), "music slider -> audio.master_bgm (got %s)" % au.master_bgm) so._on_sound_volume(0.75) _ck(is_equal_approx(au.master_sfx, 0.75), "sound slider -> audio.master_sfx (got %s)" % au.master_sfx) # --- 镜头 근/원 radio → max_dist --- (so._node("camera_short") as BaseButton).pressed.emit() _ck(so.camera_mode == 0, "camera_short -> mode 0") _ck(is_equal_approx(cam.max_dist, SystemOptionUI.CAMERA_MAX[0]), "camera short -> cam.max_dist=%s" % cam.max_dist) _ck(cam.dist <= cam.max_dist, "camera dist clamped to new max") (so._node("camera_long") as BaseButton).pressed.emit() _ck(so.camera_mode == 1 and is_equal_approx(cam.max_dist, SystemOptionUI.CAMERA_MAX[1]), "camera_long -> mode 1 / far max") # 라디오 배타성 _ck(not (so._node("camera_short") as BaseButton).button_pressed, "camera_short unset after camera_long") # --- 안개 0/1/2 radio → Environment.fog_density --- (so._node("fog_level0") as BaseButton).pressed.emit() _ck(so.fog_level == 0 and env.fog_enabled and is_equal_approx(env.fog_density, SystemOptionUI.FOG_DENSITY[0]), "fog_level0 (dense) -> env.fog_density=%s" % env.fog_density) (so._node("fog_level2") as BaseButton).pressed.emit() _ck(so.fog_level == 2 and is_equal_approx(env.fog_density, SystemOptionUI.FOG_DENSITY[2]), "fog_level2 (light) -> env.fog_density=%s" % env.fog_density) # --- 持久화: user://system_option.cfg --- _ck(FileAccess.file_exists(_cfg_path()), "cfg written") var cfg := ConfigFile.new() cfg.load(_cfg_path()) _ck(is_equal_approx(float(cfg.get_value("audio", "music_volume", -1.0)), 0.30), "cfg music_volume persisted") _ck(int(cfg.get_value("video", "fog_level", -1)) == 2, "cfg fog_level persisted") _ck(int(cfg.get_value("video", "camera_mode", -1)) == 1, "cfg camera_mode persisted") so.close() _ck(not so.is_open(), "system-option window closed") # --- 두 번째 인스턴스가 cfg 를 읽어 즉시 적용 --- var au2 := FakeAudio.new() var cam2 := FakeCam.new() get_root().add_child(au2) get_root().add_child(cam2) var env2 := Environment.new() var so2: Node = SystemOptionUI.new() get_root().add_child(so2) so2.setup(ui, assets, au2, func(): return cam2, func(): return env2) _ck(is_equal_approx(au2.master_bgm, 0.30), "reload: cfg music_volume applied on setup") _ck(is_equal_approx(cam2.max_dist, SystemOptionUI.CAMERA_MAX[1]), "reload: cfg camera_mode applied") _ck(is_equal_approx(env2.fog_density, SystemOptionUI.FOG_DENSITY[2]), "reload: cfg fog_level applied") if FileAccess.file_exists(_cfg_path()): DirAccess.remove_absolute(_cfg_path())