port: verify root pack ledger and repair runtime adapters

This commit is contained in:
shen
2026-09-24 00:18:33 -07:00
parent c84f913cfd
commit 330ec9745b
89 changed files with 17085 additions and 6808 deletions
+42 -19
View File
@@ -20,8 +20,9 @@ var _ui_next := 0
var master_sound := 1.0
var master_music := 1.0
# 3D 循环音效实例:id -> AudioStreamPlayer3D
# 3D 循环音效实例:id -> AudioStreamPlayer3D;所有 3D 播放器用于 StopAll。
var _active_3d := {}
var _all_3d: Array[AudioStreamPlayer3D] = []
func _ready() -> void:
_init_roots()
@@ -111,16 +112,23 @@ func _find_sound(rel: String) -> String:
elif rel.begins_with("d:/") or rel.begins_with("D:/"):
rel = rel.substr(3)
# 1. 尝试直接路径
if FileAccess.file_exists(rel):
return rel
# 2. 补全扩展名候选
# 补全扩展名候选
var cands := PackedStringArray([rel])
if rel.get_extension().is_empty():
cands = PackedStringArray([rel + ".wav", rel + ".mp3", rel + ".ogg"])
# 3. 在所有已知根目录中遍历查找
# 40250's CEterPackManager is the authority for sounds, as it is for models and UI images.
if ClassDB.class_exists("Metin2Pack") and Metin2Pack.is_ready():
for c in cands:
if Metin2Pack.exists(c):
return "pack://" + c
if not c.begins_with("sound/") and Metin2Pack.exists("sound/" + c):
return "pack://sound/" + c
if FileAccess.file_exists(rel):
return rel
# 开发期散文件兜底。
for root in _sound_roots:
for c in cands:
var p := root.path_join(c)
@@ -139,14 +147,21 @@ func _load_stream(path: String) -> AudioStream:
return _cache[path]
var s: AudioStream = null
var ext := path.get_extension().to_lower()
var bytes: PackedByteArray
if path.begins_with("pack://"):
bytes = Metin2Pack.get_bytes(path.substr(7))
else:
bytes = FileAccess.get_file_as_bytes(path)
if bytes.is_empty():
return null
if ext == "mp3":
var m := AudioStreamMP3.new()
m.data = FileAccess.get_file_as_bytes(path)
m.data = bytes
s = m if m.data.size() > 0 else null
elif ext == "ogg":
s = AudioStreamOggVorbis.load_from_file(path)
s = AudioStreamOggVorbis.load_from_buffer(bytes)
elif ext == "wav":
s = AudioStreamWAV.load_from_file(path)
s = AudioStreamWAV.load_from_buffer(bytes)
_cache[path] = s
return s
@@ -164,7 +179,8 @@ func play_sound_2d(rel: String, volume_scale := 1.0) -> void:
var pl := _ui_pool[_ui_next]
_ui_next = (_ui_next + 1) % _ui_pool.size()
pl.stream = stream
var vol: float = clampf(master_sound * volume_scale, 0.0, 1.0)
# SoundManager already applied the current master volume to this command.
var vol: float = clampf(volume_scale, 0.0, 1.0)
pl.volume_db = linear_to_db(vol) if vol > 0.001 else -80.0
pl.play()
@@ -181,28 +197,35 @@ func play_sound_3d(rel: String, pos: Vector3, volume_scale := 1.0, sound_id := 0
pl.stream = stream
pl.unit_size = 8.0
pl.max_distance = 80.0
var vol: float = clampf(master_sound * volume_scale, 0.0, 1.0)
var vol: float = clampf(volume_scale, 0.0, 1.0)
pl.volume_db = linear_to_db(vol) if vol > 0.001 else -80.0
add_child(pl)
_all_3d.append(pl)
pl.global_position = pos
pl.play()
if sound_id > 0:
_active_3d[sound_id] = pl
pl.finished.connect(func(): _active_3d.erase(sound_id); pl.queue_free())
else:
pl.finished.connect(pl.queue_free)
pl.finished.connect(func():
_all_3d.erase(pl)
if sound_id > 0 and _active_3d.get(sound_id) == pl:
_active_3d.erase(sound_id)
pl.queue_free())
func stop_sound_3d(sound_id: int) -> void:
if _active_3d.has(sound_id):
var pl: AudioStreamPlayer3D = _active_3d[sound_id]
if is_instance_valid(pl):
pl.stop()
_all_3d.erase(pl)
pl.queue_free()
_active_3d.erase(sound_id)
func stop_all_sound_3d() -> void:
for id in _active_3d.keys():
stop_sound_3d(id)
for pl in _all_3d:
if is_instance_valid(pl):
pl.stop()
pl.queue_free()
_all_3d.clear()
_active_3d.clear()
# --- BGM 背景音乐播放 -----------------------------------------------------
@@ -210,7 +233,6 @@ func stop_all_sound_3d() -> void:
func play_music(name: String, volume_scale := 1.0) -> void:
if name.is_empty() or name == _bgm_name:
return
_bgm_name = name
var path := name.replace("\\", "/")
if not path.is_absolute_path():
@@ -225,6 +247,7 @@ func play_music(name: String, volume_scale := 1.0) -> void:
var stream := _load_stream(path)
if stream == null:
return
_bgm_name = name
if stream is AudioStreamMP3:
stream.loop = true
@@ -233,7 +256,7 @@ func play_music(name: String, volume_scale := 1.0) -> void:
_bgm[nxt].volume_db = -40.0
_bgm[nxt].play()
var target_vol: float = clampf(master_music * volume_scale, 0.0, 1.0)
var target_vol: float = clampf(volume_scale, 0.0, 1.0)
var target_db: float = linear_to_db(target_vol) if target_vol > 0.001 else -80.0
if _bgm_fade_tween and _bgm_fade_tween.is_valid():
+34
View File
@@ -0,0 +1,34 @@
extends SceneTree
var failures := 0
func _initialize() -> void:
call_deferred("_run")
func _check(ok: bool, detail: String) -> void:
if not ok:
failures += 1
printerr("FAIL: " + detail)
func _run() -> void:
_check(AssetRoot.pack_ready(), "40250 pack unavailable")
var driver: Node = preload("res://audio_driver.gd").new()
root.add_child(driver)
var sound := "sound/ambience/waterfall.wav"
var path: String = driver._find_sound(sound)
_check(path == "pack://" + sound, "sound must resolve through 40250 pack")
var stream: AudioStream = driver._load_stream(path)
_check(stream != null, "packed WAV must decode")
if stream != null:
driver.set_sound_volume(0.5)
driver.play_sound_2d(sound, 0.5)
var player: AudioStreamPlayer = driver._ui_pool[0]
_check(absf(player.volume_db - linear_to_db(0.5)) < 0.01,
"sound volume was applied more than once")
driver.play_sound_3d(sound, Vector3.ZERO, 0.5)
_check(driver._all_3d.size() == 1, "3D sound not tracked")
driver.stop_all_sound_3d()
_check(driver._all_3d.is_empty(), "StopAllSound3D left a player running")
driver.free()
print("PASS: audio_driver_test" if failures == 0 else "FAIL: audio_driver_test")
quit(0 if failures == 0 else 1)