Files
shenleiandClaude Sonnet 5 9732f2799e 40250 classic: increment 50 (W4) — map BGM selection + background volume save/restore
§9.1 map BGM selection (bgm_director.gd):
- server bgm_changed(name, volume): non-empty name plays it as field music;
  empty name falls back to musicInfo.fieldMusic (METIN2THEMA = "M2BG.mp3")
- volume < 0 (server unspecified, GC_MAIN_CHARACTER3_BGM) -> default
  1/5*0.1 = 0.02; otherwise server volume; volume applied before play_bgm()
  fade-in (matches game.py:190 SetMusicVolume/SetSoundVolume then FadeInMusic)
- connect M2Client.world_reset -> re-run selection on map change
- new musicinfo.gd: METIN2THEMA/loginMusic/createMusic/selectMusic/fieldMusic
  constants + save/load_last_play_field_music -> user://BGM/lastplay.inf

§9.2 background/foreground volume save-restore:
- audio.gd: save_volume()/restore_volume() (backup fields echo reference
  m_fBackupMusicVolume / m_fBackupSoundVolume) + set_music_volume()
- app_lifecycle.gd: _enter_background() uses save_volume() + mute instead of
  stop_bgm(); _exit_background() calls restore_volume(); _bgm_name never cleared

§9.3 lifecycle ownership: DOC ONLY — design confirmed, deferred to Phase 2 / W0
(AppFlow sole lifecycle owner; M2Client drops NOTIFICATION_* keeps suspend/resume).
game_scene.gd / app_flow.gd / m2_client.* left untouched per workflow constraints.

Tests: bgm_test.gd (new) PASS; gamescene_test / netplay_test / p9_test green.
Docs: CLIENT-GAP.md increment 50 bullet + W4 progress row; CLIENT-GAP-FIX.md
§9.1 §9.2 状态/改动/测试/验收, §9.3 deferred note, C.5 batch record.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014yvAPqPivoY7vmBbzgqK4W
2026-09-02 15:31:58 +09:00

82 lines
3.1 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BgmDirector —— 把 M2Client.bgm_changed 信号翻译成 Audio 的 BGM 播放。
#
# 存在的理由:§9.1 的地图 BGM 消费点,从 net_world.gd 里拆出来,避免 W2(可见性)
# 和 W4(音频)同时改 net_world.gd。地图 → 曲目解析和音量应用在这里(§9.1)。
#
# 选曲逻辑对标 game.py:190GameWindow.Open 内):
# snd.SetMusicVolume(...); snd.SetSoundVolume(...) # 先应用音量
# name = net.GetFieldMusicFileName()
# if name: snd.FadeInMusic("BGM/" + name)
# elif musicInfo.fieldMusic: snd.FadeInMusic("BGM/" + musicInfo.fieldMusic)
# 默认音量 gs_fieldMusic_volume = 1.0f/5.0f*0.1f = 0.02f(服务器未下发时)。
#
# 用法:
# var bd := preload("res://bgm_director.gd").new()
# add_child(bd)
# bd.bind(client, audio)
extends Node
const MusicInfo = preload("res://musicinfo.gd")
# gs_fieldMusic_volume 默认值(PythonNetworkStreamPhaseLoading.cpp:299)。
const DEFAULT_FIELD_MUSIC_VOLUME := 1.0 / 5.0 * 0.1 # = 0.02
var _client: Node
var _audio: Node
# 服务器最近一次下发的 BGM(曲目 id 或路径)和音量(<0 表示未指定)。
var current_track := ""
var current_volume := -1.0
func bind(client: Node, audio: Node) -> void:
_client = client
_audio = audio
if _client and _client.has_signal("bgm_changed"):
_client.bgm_changed.connect(_on_bgm_changed)
# 换图(§1.3):world_reset 后重跑选曲逻辑。新图的 BGM 包到达前沿用当前曲目。
if _client and _client.has_signal("world_reset"):
_client.world_reset.connect(_on_world_reset)
func _on_bgm_changed(name: String, volume: float) -> void:
# M2Client 已在 EntityStore 侧做音量保留(BGM3 只带名、BGM4 带名+音量),
# 这里拿到的 volume 就是「有效音量」,<0 仅表示从未收到过 BGM4。
current_track = name
current_volume = volume
_select()
func _on_world_reset() -> void:
_select()
# game.py:190 的三行选曲 + 先置音量。
func _select() -> void:
if _audio == null:
return
# 1) 选曲:服务端名优先,否则回落 musicInfo.fieldMusicMETIN2THEMA = "M2BG.mp3")。
var track := current_track
if track == "":
track = String(MusicInfo.fieldMusic)
# 2) 音量:服务端未指定(<0)用默认 0.02,否则用服务端值。
var vol := current_volume if current_volume >= 0.0 else DEFAULT_FIELD_MUSIC_VOLUME
vol = clampf(vol, 0.0, 1.0)
# 3) 先应用音量再淡入:Audio.play_bgm() 的淡入目标是 linear_to_db(master_bgm)
# 对标 game.py 先 SetMusicVolume/SetSoundVolume 再 FadeInMusic。
# 声音(SFX)音量在参考里取自系统设置(systemSetting.GetSoundVolume),
# 不随 BGM 包下发,这里不改 master_sfx。
if "master_bgm" in _audio:
_audio.master_bgm = vol
if _audio.has_method("set_music_volume"):
_audio.set_music_volume(vol)
if track == "":
if _audio.has_method("stop_bgm"):
_audio.stop_bgm()
return
if _audio.has_method("play_bgm"):
_audio.play_bgm(track)
# musicInfo.SaveLastPlayFieldMusic 语义:记录本次战场曲目。
MusicInfo.save_last_play_field_music(track)