# bgm_test —— §9.1 地图 BGM 选曲 + §9.2 前后台音量存/恢复的 headless 自检。 # godot --headless --path project --script bgm_test.gd # exit 0 = pass。 extends SceneTree const BgmDirector = preload("res://bgm_director.gd") const Audio = preload("res://audio.gd") const AppLifecycle = preload("res://app_lifecycle.gd") const MusicInfo = preload("res://musicinfo.gd") const DEFAULT_VOL := 1.0 / 5.0 * 0.1 # 0.02 # 假 M2Client:只发 §9.1 关心的两个信号。 class FakeClient extends Node: signal bgm_changed(name: String, volume: float) signal world_reset() # 假 Audio:记录 play_bgm / stop_bgm 调用与音量,够 director 断言用。 class FakeAudio extends Node: var master_bgm := 0.6 var master_sfx := 0.9 var _bgm_name := "" var played: Array[String] = [] var stopped := 0 func play_bgm(name: String, _fade := 1.2) -> void: if name == _bgm_name: return _bgm_name = name played.append(name) func stop_bgm(_fade := 1.0) -> void: _bgm_name = "" stopped += 1 func set_music_volume(v: float) -> void: master_bgm = clampf(v, 0.0, 1.0) var _fail := 0 func _ck(c: bool, m: String) -> void: if not c: _fail += 1 printerr("FAIL: " + m) func _init() -> void: _test_select_server_volume() _test_select_default_volume() _test_select_empty_falls_back() _test_world_reset_reruns() _test_musicinfo_lastplay_roundtrip() _test_background_save_restore() if _fail == 0: print("PASS: bgm_test (§9.1 map BGM select + §9.2 volume save/restore)") quit(0) else: printerr("%d check(s) failed" % _fail) quit(1) func _mk_director() -> Array: var client := FakeClient.new() var audio := FakeAudio.new() var bd := BgmDirector.new() get_root().add_child(client) get_root().add_child(audio) get_root().add_child(bd) bd.bind(client, audio) return [client, audio, bd] # §9.1:服务端给了名字 + 音量 -> 用服务端音量并播放该曲。 func _test_select_server_volume() -> void: var t := _mk_director() var client: FakeClient = t[0] var audio: FakeAudio = t[1] client.bgm_changed.emit("pvp_bgm.mp3", 0.5) _ck(audio.played == ["pvp_bgm.mp3"], "server name played, got %s" % [audio.played]) _ck(is_equal_approx(audio.master_bgm, 0.5), "server volume applied, got %f" % audio.master_bgm) _ck(audio.stopped == 0, "no stop_bgm on server-provided track") t[0].free(); t[1].free(); t[2].free() # §9.1:服务端给了名字但音量 <0(GC_MAIN_CHARACTER3_BGM,未收 BGM4)-> 默认 0.02。 func _test_select_default_volume() -> void: var t := _mk_director() var client: FakeClient = t[0] var audio: FakeAudio = t[1] client.bgm_changed.emit("field_a.mp3", -1.0) _ck(audio.played == ["field_a.mp3"], "name played on unspecified volume, got %s" % [audio.played]) _ck(is_equal_approx(audio.master_bgm, DEFAULT_VOL), "default 0.02 applied, got %f" % audio.master_bgm) t[0].free(); t[1].free(); t[2].free() # §9.1:服务端名为空 -> 回落 musicInfo.fieldMusic(METIN2THEMA = "M2BG.mp3")。 func _test_select_empty_falls_back() -> void: var t := _mk_director() var client: FakeClient = t[0] var audio: FakeAudio = t[1] client.bgm_changed.emit("", -1.0) _ck(audio.played == [String(MusicInfo.fieldMusic)], "empty name falls back to fieldMusic, got %s" % [audio.played]) _ck(String(MusicInfo.fieldMusic) == "M2BG.mp3", "METIN2THEMA constant is M2BG.mp3") _ck(is_equal_approx(audio.master_bgm, DEFAULT_VOL), "default 0.02 on fallback, got %f" % audio.master_bgm) t[0].free(); t[1].free(); t[2].free() # §9.1 / §1.3:换图(world_reset)重跑选曲逻辑。 func _test_world_reset_reruns() -> void: var t := _mk_director() var client: FakeClient = t[0] var audio: FakeAudio = t[1] var bd: BgmDirector = t[2] _ck(client.world_reset.is_connected(bd._on_world_reset), "director connected to world_reset") client.bgm_changed.emit("map_a.mp3", 0.4) # warp:world_reset 先到(旧曲目仍在 store 里),随后新图的 BGM 包。 client.world_reset.emit() _ck(audio.played == ["map_a.mp3"], "world_reset keeps current track, got %s" % [audio.played]) client.bgm_changed.emit("map_b.mp3", 0.2) _ck(audio.played == ["map_a.mp3", "map_b.mp3"], "new map BGM played, got %s" % [audio.played]) _ck(is_equal_approx(audio.master_bgm, 0.2), "new map volume applied, got %f" % audio.master_bgm) t[0].free(); t[1].free(); t[2].free() # §9.1:musicInfo.SaveLastPlayFieldMusic / LoadLastPlayFieldMusic 往返。 func _test_musicinfo_lastplay_roundtrip() -> void: MusicInfo.save_last_play_field_music("last_field.mp3") _ck(MusicInfo.load_last_play_field_music() == "last_field.mp3", "lastplay.inf roundtrip, got %s" % MusicInfo.load_last_play_field_music()) # §9.2:后台保存音量 + 静音,前台恢复;_bgm_name 不变,同一首继续播。 func _test_background_save_restore() -> void: var client := FakeClient.new() var audio := Audio.new() var life := AppLifecycle.new() get_root().add_child(audio) audio.setup("res://__no_assets__") # 无资源,play_bgm 只置名不出声 get_root().add_child(life) life.pause_tree_on_background = false # 别把测试树暂停了 life.background_max_fps = 0 life.bind(null, audio) audio.master_bgm = 0.6 audio.master_sfx = 0.9 # 模拟「某首战场曲目正在播放」(headless 无资源,不实际解码)。 audio._bgm_name = "M2BG.mp3" var name_before := audio._bgm_name _ck(name_before == "M2BG.mp3", "bgm name set before background, got %s" % name_before) life._enter_background() _ck(is_equal_approx(audio.master_bgm, 0.0), "music muted in background, got %f" % audio.master_bgm) _ck(audio._volume_saved, "save_volume ran (backup taken)") _ck(is_equal_approx(audio._backup_music_volume, 0.6), "backup music volume, got %f" % audio._backup_music_volume) _ck(is_equal_approx(audio._backup_sound_volume, 0.9), "backup sound volume, got %f" % audio._backup_sound_volume) _ck(audio._bgm_name == name_before, "_bgm_name unchanged in background, got %s" % audio._bgm_name) life._exit_background() _ck(is_equal_approx(audio.master_bgm, 0.6), "music volume restored, got %f" % audio.master_bgm) _ck(is_equal_approx(audio.master_sfx, 0.9), "sound volume restored, got %f" % audio.master_sfx) _ck(audio._bgm_name == name_before, "_bgm_name still unchanged after restore, got %s" % audio._bgm_name) _ck(not audio._volume_saved, "backup flag cleared after restore") client.free(); life.free(); audio.free()