This commit is contained in:
Nicholas Butzke
2026-08-02 02:20:02 -04:00
parent 61669627db
commit 922983429e
226 changed files with 34032 additions and 18521 deletions
+257
View File
@@ -0,0 +1,257 @@
extends SceneTree
## Runtime release gate for the premium audio pass.
##
## Uses a real Forward+ match so it verifies autoload ordering, imported audio
## resources, a spawned player's movement players, and a live weapon loadout.
var _frames := 0
var _phase := "menu"
var _failures: Array[String] = []
const REQUIRED_EVENTS := [
"ak47_fire", "m4_fire", "mp7_fire", "dmr_fire", "awp_fire",
"shotgun_fire", "nailgun_fire", "plasma_fire", "rocket_fire",
"swarm_fire", "mortar_fire", "knife_swing", "shotgun_reload",
"explosion", "bullet_impact",
"footstep_concrete", "footstep_metal", "footstep_wood", "footstep_glass",
"wind", "slide", "wallrun", "dash", "jump", "double_jump", "vault", "land",
"grapple_launch", "grapple_latch", "grapple_reel",
"ui_hover", "ui_click", "ui_confirm", "ui_error", "ui_equip",
]
func _initialize() -> void:
change_scene_to_file("res://ui/main_menu/main_menu.tscn")
func _process(_delta: float) -> bool:
_frames += 1
if _phase == "menu" and _frames == 50:
_verify_menu_music()
_verify_manager()
var network = root.get_node_or_null("NetworkManager")
if network and network.has_method("start_singleplayer_match"):
network.start_singleplayer_match(GameMode.DEATHMATCH)
else:
_fail("NetworkManager cannot start the runtime audio match")
change_scene_to_file("res://scenes/maps/test_level/test_level.tscn")
_phase = "match"
_frames = 0
elif _phase == "match" and _frames == 180:
_verify_live_player()
_phase = "drain"
_frames = 0
unload_current_scene()
elif _phase == "drain" and _frames >= 90:
_finish()
return false
func _verify_menu_music() -> void:
var found := false
if current_scene:
for candidate in current_scene.find_children("*", "AudioStreamPlayer", true, false):
var player := candidate as AudioStreamPlayer
if player.bus == "Music":
found = true
_check(player.playing, "menu music is playing")
_check(player.stream is AudioStreamOggVorbis,
"menu music is an imported Ogg stream")
if player.stream is AudioStreamOggVorbis:
_check((player.stream as AudioStreamOggVorbis).loop,
"menu music loops")
break
_check(found, "main menu owns a Music-bus player")
func _verify_manager() -> void:
var am = root.get_node_or_null("AudioManager")
_check(am != null, "AudioManager autoload exists")
if am == null:
return
for event in REQUIRED_EVENTS:
_check(am.has_sound(event), "event resolves: %s" % event)
_check(am.weapon_sound_id("Double Barrel") == "shotgun_fire",
"multiplayer shotgun broadcast resolves to its fire family")
var expected_sends := {
"SFX": "Master", "Weapons": "SFX", "Explosions": "SFX",
"Impacts": "SFX", "Footsteps": "SFX", "Movement": "SFX",
"Ambience": "SFX", "UI": "SFX", "Wind": "SFX", "Music": "Master",
}
for bus_name in expected_sends:
var bus := AudioServer.get_bus_index(bus_name)
_check(bus >= 0, "bus exists: %s" % bus_name)
if bus >= 0:
_check(AudioServer.get_bus_send(bus) == expected_sends[bus_name],
"%s routes to %s" % [bus_name, expected_sends[bus_name]])
var master := AudioServer.get_bus_index("Master")
_check(_bus_has_effect(master, "AudioEffectHardLimiter"),
"Master has a hard limiter")
_check(_bus_has_effect(AudioServer.get_bus_index("Weapons"),
"AudioEffectCompressor"), "Weapons has transient compression")
_check(_bus_has_effect(AudioServer.get_bus_index("Explosions"),
"AudioEffectCompressor"), "Explosions has body compression")
var loop_stream: AudioStream = am.stream_for("wind")
_check(loop_stream is AudioStreamRandomizer, "wind resolves through variation stream")
if loop_stream is AudioStreamRandomizer:
var randomizer := loop_stream as AudioStreamRandomizer
_check(randomizer.streams_count >= 1, "wind has a source stream")
var child := randomizer.get_stream(0)
_check(child is AudioStreamWAV, "wind source is WAV")
if child is AudioStreamWAV:
var wav := child as AudioStreamWAV
_check(wav.loop_mode == AudioStreamWAV.LOOP_FORWARD,
"wind source has forward looping enabled")
_check(wav.loop_end > 0, "wind source has an explicit loop end")
var first = am.play_ui("ui_hover")
var suppressed = am.play_ui("ui_hover")
_check(first != null, "UI hover plays")
_check(suppressed == null, "UI hover chatter is rate-limited")
var click = am.play_ui("ui_click")
_check(click != null and click.bus == "UI", "UI click plays on the UI bus")
var explosion = am.play_3d("explosion", Vector3.ZERO)
_check(explosion != null and explosion.bus == "Explosions",
"explosion plays on the Explosions bus")
for material in ["concrete", "metal", "wood", "glass"]:
var surface := Node.new()
surface.set_meta("acoustic_material", material)
_check(Acoustics.classify(surface) == material,
"surface classifier preserves %s" % material)
surface.free()
func _verify_live_player() -> void:
var ambience := current_scene.get_node_or_null("AmbientBed") \
if current_scene else null
_check(ambience == null, "level has no always-on broadband ambience")
var player = null
for candidate in root.find_children("*", "CharacterBody3D", true, false):
if candidate.has_method("get_visual_model") \
and candidate.is_multiplayer_authority():
player = candidate
break
_check(player != null, "single-player match spawned the local player")
if player == null:
return
_check(player.has_method("surface_event"), "player exposes material event lookup")
var foot_event: String = player.surface_event("footstep")
_check(foot_event in [
"footstep_concrete", "footstep_metal", "footstep_wood", "footstep_glass"],
"live floor resolves to a footstep family (%s)" % foot_event)
player.play_footstep(8.0)
_check(player.footstep_player.bus == "Footsteps",
"local footsteps use the Footsteps bus")
_check(player.footstep_player.playing, "local material footstep plays")
player.update_slide_audio(14.0)
_check(player.slide_player.bus == "Movement", "slide uses the Movement bus")
_check(player.slide_player.stream is AudioStreamRandomizer,
"slide uses the mastered looping family")
player.update_wallrun_audio(14.0, Vector3.LEFT)
_check(player.wallrun_player.bus == "Movement", "wall-run uses the Movement bus")
_check(player.wind_player.bus == "Wind", "speed wind uses the independent Wind bus")
_check(player.grapple_shoot_player.bus == "Movement",
"grapple launch uses the Movement bus")
_check(player.grapple_latch_player.bus == "Movement",
"grapple latch uses the Movement bus")
_check(player.grapple_swing_player.bus == "Movement",
"grapple reel uses the Movement bus")
_check(player.jump_player.stream != player.double_jump_player.stream,
"ground jump and powered double jump use distinct masters")
var grapple_streams := [
player.grapple_shoot_player.stream,
player.grapple_latch_player.stream,
player.grapple_swing_player.stream,
]
_check(grapple_streams[0] != grapple_streams[1]
and grapple_streams[0] != grapple_streams[2]
and grapple_streams[1] != grapple_streams[2],
"grapple launch, latch and reel use three distinct masters")
_check(player.jump_player.stream not in grapple_streams
and player.double_jump_player.stream not in grapple_streams
and player.dash_player.stream not in grapple_streams,
"grapple stages do not reuse jump or jet-thrust masters")
_check(_randomizer_has_loop(player.grapple_swing_player.stream),
"grapple reel resolves to an explicitly looping cable stream")
player._on_movement_event("grapple_shoot", {})
_check(player.grapple_shoot_player.playing,
"grapple shoot event plays the cable launcher")
player._on_movement_event("grapple_latch", {})
_check(player.grapple_latch_player.playing,
"grapple latch event plays the hook impact")
_check(player._jet_vfx != null and player._jet_vfx.get_flame_count() == 4,
"live player owns exactly four jet flames")
var jet_before: float = player._jet_vfx._burst_left
player._on_movement_event("jump", {})
_check(is_equal_approx(player._jet_vfx._burst_left, jet_before),
"ordinary jump does not ignite the jets")
player._on_movement_event("double_jump", {})
_check(player._jet_vfx._burst_left > 0.0,
"double jump ignites the four-jet burst")
var managers: Array[Node] = player.find_children(
"WeaponManager", "WeaponManager", true, false)
_check(not managers.is_empty(), "live player has a WeaponManager")
if not managers.is_empty():
var manager = managers[0]
var checked_weapons := 0
for weapon in manager.weapons.values():
if weapon and "fire_sound" in weapon and weapon.fire_sound:
checked_weapons += 1
_check(weapon.fire_sound.bus == "Weapons",
"%s fire routes to Weapons" % weapon.weapon_name)
_check(weapon.fire_sound.stream is AudioStreamRandomizer,
"%s uses the mastered variation family" % weapon.weapon_name)
_check(weapon.fire_sound.max_polyphony >= 4,
"%s shots keep overlapping body/tails" % weapon.weapon_name)
_check(checked_weapons >= 3, "at least three live weapon players verified")
func _randomizer_has_loop(stream: AudioStream) -> bool:
if not stream is AudioStreamRandomizer:
return false
var randomizer := stream as AudioStreamRandomizer
if randomizer.streams_count < 1:
return false
var child := randomizer.get_stream(0)
return child is AudioStreamWAV \
and (child as AudioStreamWAV).loop_mode == AudioStreamWAV.LOOP_FORWARD
func _bus_has_effect(bus: int, effect_class: String) -> bool:
if bus < 0:
return false
for i in AudioServer.get_bus_effect_count(bus):
var effect := AudioServer.get_bus_effect(bus, i)
if effect and effect.is_class(effect_class):
return true
return false
func _check(condition: bool, label: String) -> void:
if condition:
print(" PASS: ", label)
else:
_fail(label)
func _fail(label: String) -> void:
_failures.append(label)
printerr("AUDIO_FIDELITY FAIL: ", label)
func _finish() -> void:
if _failures.is_empty():
print("AUDIO_FIDELITY PASSED")
quit(0)
else:
printerr("AUDIO_FIDELITY failures=", _failures.size())
quit(1)