These files were loaded only by their own test_*_parity.gd and never by the runtime (transitively checked, incl. client_phase_integration_system). Removes 76 manifest implementation/evidence references across 18 contracts; contract docs get a note that conclusions based on them are void. Live systems kept: chest, consumable, item_attr, metin_socket, whisper_chat. Full headless suite: no new failures (7 failing + 5 headless-hanging render tests are identical before the deletion). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
11 KiB
11 KiB
audio.bgm_ambience_3d —— BGM、区域环境音、角色音效、3D 监听器和前后台恢复
状态:PARTIAL
本合同检查 40250 的 2D/3D/Stream 三类声音实例、BGM 音乐状态机、区域环境声、角色动作音效、监听器坐标/方向、音量曲线、限频和前后台生命周期。判断标准是播放实例的分配、状态转换、坐标/音量公式、重复播放限制、地图卸载和恢复副作用一致;“测试能播放”不等于 SoundManager 生命周期等价。
40250 参考调用链
MilesLib/SoundManager.cpp/SoundManager2D.cpp/SoundManager3D.cpp/SoundManagerStream.cppCreate按 2D、Stream、3D 顺序初始化驱动;Destroy先停止音乐和 3D 实例,再关闭 listener/provider/driver。- 2D/3D 音效使用固定实例池,实例完成后才可复用;3D 位置按
(world-listener)/soundScale,环境声使用ambienceSoundScale。 - 角色音效可按 5000cm 半径过滤,并按文件名限制 0.3 秒内重复播放;
StopAllSound3D同时清空历史。
MilesLib/SoundManager.cpp- BGM 维护多个
TMusicInstance,状态为 OFF、FADE_IN、FADE_LIMIT_OUT、FADE_OUT、PLAY;Update每帧递增/递减音量,达到边界后切换状态或停止实例。 FadeInMusic先淡出已有音乐;FadeOutAllMusic为每个活动实例设置淡出;FadeLimitOutMusic保留目标音量。SaveVolume同时把音乐和音效音量置零并保存备份,RestoreVolume恢复两者;不是只停止或只静音 BGM。
- BGM 维护多个
MilesLib/SoundManager3D.cpp/PythonSoundManagerModule.cpp- 暴露
PlaySound、PlaySound3D、PlayMusic、FadeIn/FadeOut、StopAllSound、音乐/音效音量、SoundScale 和 AmbienceSoundScale。 - 3D listener 维护位置、方向、up 和速度;环境声由
CArea::UpdateAroundAmbience每次更新。
- 暴露
GameLib/Area.cpp/Area.hTAmbienceInstance从 AreaAmbienceData/Property 读取位置、范围、最大音量半径、LOOP/ONCE/STEP 和步进随机间隔。- LOOP 在范围内创建循环实例并按距离线性衰减;离开范围停止并清理索引。ONCE 只在进入范围时播放,STEP 按时间到期播放,离开时重置下一次时间。
当前端实现映射
project/audio.gd- 已有 BGM 双播放器、UI 音效池、AudioStreamPlayer3D、listener 重定位、200/1000 缩放、音量比例曲线、
.mss60FPS 事件、角色音效距离/0.3 秒限频,以及 Area LOOP/ONCE/STEP。 - 3D 播放器按需创建,没有 40250 固定实例池/Provider 生命周期;Godot
unit_size/max_distance衰减也不是 Miles provider 的同一声学模型。 - BGM 使用 Tween 交叉淡入淡出,不是
TMusicInstance::Update的逐帧状态机;加载失败时_bgm_name先写入,存在“资源失败后同名请求被跳过”的状态风险。
- 已有 BGM 双播放器、UI 音效池、AudioStreamPlayer3D、listener 重定位、200/1000 缩放、音量比例曲线、
project/bgm_director.gd/project/game_scene.gd- 已按
bgm_changed和world_reset选曲,服务器音量优先,缺省回落musicInfo.fieldMusic,并保存最近战场曲目。 - 生产链已创建 Audio、BgmDirector 并在每帧更新 listener/区域环境声;地图切换时会停止 BGM,但没有完整证明参考端多音乐实例的淡出状态被逐个清理。
- 已按
project/app_lifecycle.gd- 已在后台保存并恢复音量、暂停树、降低 FPS,保持 BGM 名称。
- 后台入口调用
save_volume后同步执行set_music_volume(0.0)和set_sound_volume(0.0);恢复仍由restore_volume一次恢复两类音量。
project/game_scene.gd_exit_tree在卸载 native world 前调用Audio.shutdown(),停止 BGM/3D 音效、解绑播放器 stream 并清空声音缓存,覆盖退出时的资源释放边界。
formats/area_data.*/extension/src/metin2_world.cpp- 已读取 AreaAmbienceData、
.pra属性和playtype/range/maxvolume/playinterval,按流式 tile 暴露 ambience source;world unload 会移除来源。 - 来源数据和播放状态由不同节点维护,地图卸载/快速切图时音频实例和来源索引的生产级清理尚未有组合测试。
- 已读取 AreaAmbienceData、
分支等价矩阵
| 40250 判据/副作用 | 当前实现 | 结论 |
|---|---|---|
| 2D/UI/3D/Stream 三类初始化、实例复用和销毁 | Audio 创建 BGM/UI/3D 节点,使用 Godot 动态播放器 | 部分等价;缺少固定实例池、Miles provider/driver 生命周期和完整销毁证据 |
| BGM 多实例 OFF/FADE_IN/FADE_LIMIT_OUT/FADE_OUT/PLAY 状态机 | 双播放器 Tween 交叉淡入淡出 | 部分等价;目标可听结果近似,但状态/边界/多个音乐实例和每帧速度公式不一致 |
| FadeIn 先处理旧曲、FadeLimitOut、FadeOutAll | 有对应方法和淡出 Tween | 部分等价;没有逐实例状态快照和停止时序证明,加载失败状态回滚也不完整 |
| 音量比例/等级曲线、音乐/音效独立音量 | ratio_to_apply_volume、grade 和 UI 设置测试通过 |
基础公式等价;后台 BGM/SFX 同时静音与恢复已有回归,真实 3D 播放实例仍需独立证据 |
| SaveVolume/RestoreVolume 同时静音和恢复 BGM/SFX | 保存两类值,后台同时调用 set_music_volume(0)/set_sound_volume(0),前台调用 restore_volume |
基础行为等价;真实 Miles provider 实例和 3D 播放器清理仍需独立证据 |
| listener 位置/方向、200/1000 缩放和 3D 播放 | GameScene._process 更新 listener,Audio 重定位实例 |
部分等价;单位与主要公式存在,Godot attenuation/provider 行为不是 Miles 1:1 |
角色动作 .mss 事件、5000cm 距离和 0.3s 限频 |
PlayerView/Audio 已实现,相关测试通过 | 基础路径通过;远端角色、全部动作事件和实例池耗尽/失败回退未覆盖 |
| Area LOOP/ONCE/STEP、距离衰减和离开范围清理 | world source + update_ambience_sources 已实现 |
部分等价;A3 真实来源测试通过,但快速换图、音频实例释放和多 source 乱序缺少证据 |
| 地图 BGM/区域声/音效在切图、失焦、暂停、重连后恢复 | BGM 停止、listener/ambient 每帧更新、后台 BGM/SFX 恢复存在 | 部分等价;跨图活动实例清理和真实 3D 播放器释放尚未形成生产级闭环 |
已执行测试
project/audio_miles_test.gd:通过;覆盖 200/1000 缩放、音量曲线、.mss解析、角色音效距离/限频和环境声实例基本路径。project/ambience_test.gd:通过;A3 真实地图来源解析出 1 个 LOOP 环境声,范围、类型和声音路径保持。project/bgm_test.gd:通过;覆盖地图 BGM 选曲、服务端音量、默认回落、换图信号,以及前后台 BGM/SFX 音量保存、同时静音和恢复。project/rendering_scenario_test.gd:通过;Debug 原生库退出无ObjectDB音频资源泄漏,验证GameScene._exit_tree -> Audio.shutdown的退出边界。project/test_bgm_jukebox_parity.gd:18 passed、0 failed;覆盖点唱机曲目注册、停止、音量钳制、地图默认和覆写恢复,不覆盖真实 Audio 实例状态机。project/app_flow_lifecycle_test.gd:通过;覆盖 AppLifecycle 单一属主和断线重连流程,不覆盖真实音频实例释放。project/system_option_ui_test.gd:通过;覆盖音量设置控件绑定,不覆盖后台和播放失败边界。
Deep audit round 2026-09-21
Fresh regression results
audio_miles_test.gd、ambience_test.gd、bgm_test.gd、test_bgm_jukebox_parity.gd18/18、app_flow_lifecycle_test.gd、system_option_ui_test.gd均退出码 0。- 回归覆盖了 3D 缩放/限频、A3 环境声、地图 BGM 选择、点唱机覆盖/恢复、生命周期属主和设置绑定;FakeAudio 仍不能证明真实播放实例状态机。
Static parity conclusion
- BGM/区域环境声/角色
.mss音效的主要入口存在,但 Godot 动态播放器/Tween 不等价于 40250 固定实例池、Provider 和TMusicInstance状态机。 app_lifecycle.gd后台路径已同步静音并恢复 BGM/SFX;加载失败后_bgm_name可能阻止同名重试,跨图快速切换时来源索引和播放器释放仍缺少生产级证据。- listener、缩放和 0.3s/5000cm 规则有局部验证,但远端 Actor 动作音效、实例池耗尽、失焦/暂停/重连/退出清理和 Godot attenuation 与 Miles provider 的边界未闭合。
Active source group review
- 对 Visual Studio
MilesLib活跃编译单元逐组核对后,参考链补充确认:CSoundManager2D/3D/Stream::Initialize/Destroy创建并释放固定实例池;CSoundData维护 pack-backed 数据缓存和 access/play time;CSoundInstance2D/3D/Stream分别处理 SetSound、Play/Stop、位置/方向/速度与音量;CSoundManager负责 listener、距离缩放、0.3 秒限频、环境声、音乐实例索引和多状态淡入淡出。 - 当前端 Audio 的动态播放器和 Tween 只覆盖可听结果的部分路径,尚未证明固定池、sound data cache、播放失败/空槽、逐实例停止和 MusicIndex 状态机等副作用一致;本组静态核对完成,合同仍为
PARTIAL。
Implementation fix round 2026-09-22T08:50Z
- 修复前
bgm_test.gd新增的 40250SaveVolume回归失败:进入后台后master_bgm=0,但master_sfx=0.9。 - 按
CSoundManager::SaveVolume的顺序,AppLifecycle._enter_background在保存备份后同时调用set_music_volume(0.0)与set_sound_volume(0.0);_exit_background继续由restore_volume同时恢复两者。 - 修复后
bgm_test.gd、audio_miles_test.gd、app_flow_lifecycle_test.gd、disconnect_world_reset_test.gd、netbridge_test.gd均通过;渲染退出回归无ObjectDB泄漏。 - 该轮只闭合后台音量副作用和退出音频缓存清理,BGM 多实例状态机、Miles 固定实例池、真实 3D 衰减/Provider、快速换图来源清理仍保持
PARTIAL。
本轮仍为 PARTIAL,完成后台音量和退出清理的实现及第二轮证据登记。
已确认差异和未验证项
- 验证正在播放的 3D 实例不会绕过 master SFX,并补真实设备/实例路径的后台静音回归。
- 建立 BGM 多实例状态快照测试,覆盖 FadeIn、FadeLimitOut、FadeOut、FadeOutAll、相同曲目重入、加载失败回滚和切图清理。
- 明确 Godot 3D 衰减与 Miles provider 的适配边界,至少固定
unit_size/max_distance、监听器方向/速度和实例池耗尽行为。 - 增加真实流式地图快速切换、来源删除、重复 key、LOOP/ONCE/STEP 乱序和退出时无悬挂播放器的测试。
- 补齐远端 Actor 的动作音效触发、重连/死亡/换图清理和资源缺失回退证据。
下一轮验证入口
- 先审计
lifecycle.platform_release,核对 Windows 窗口、导出、自包含资源、崩溃处理和发布门禁。 - 回到实现阶段时,优先建立 BGM 多实例状态机和真实 3D 播放器清理测试,再处理固定实例池/Provider 的适配边界。
2026-09-22 死代码删除
以下文件只被自身测试引用、运行时从不加载,已删除;本文中以它们为实现或证据的结论作废,相关行为需按 40250 源码单元重新移植:test_bgm_jukebox_parity.gd。