Files
aetherbound-guild/runtime/tests/fg2/audio_recording.gd
T

168 lines
5.7 KiB
GDScript

extends SceneTree
const Controller = preload("res://campaign/fg2_graybox_controller.gd")
const Fixture = preload("res://campaign/fg2_fixture.gd")
const VIEWPORT := Vector2i(844, 390)
const MIN_CONTENT_FRAMES := 650
const TARGET_CONTENT_FRAMES := 780
const MAX_CONTENT_FRAMES := 900
const REQUIRED_ASSETS := [
"FG2-SFX-COMMIT",
"FG2-SFX-FORECAST",
"FG2-SFX-IMPACT",
"FG2-SFX-GUARD",
"FG2-SFX-CASUALTY",
"FG2-SFX-VICTORY",
"FG2-SFX-RECOVERY",
]
var failures: Array[String] = []
var experience
var parsed_touches := 0
var parsed_drags := 0
var recording_frames := 0
var heard_assets: Dictionary = {}
var heard_events: Dictionary = {}
func _initialize() -> void:
call_deferred("run_recording")
func run_recording() -> void:
root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_EXPAND
root.content_scale_size = VIEWPORT
root.size = VIEWPORT
experience = Controller.new()
experience.battle_auto_advance = false
experience.muted = false
experience.size = Vector2(VIEWPORT)
experience.configure_entry(Fixture.canonical_market_state())
root.add_child(experience)
await hold(60)
var order: Array = Array(experience.adapter.market.state.current_run.deployed_recruit_ids).duplicate()
await drag("FG2CompanyTarget_%s" % String(order[-1]), "FG2CompanyTarget_%s" % String(order[0]))
await hold(24)
var route_id := Fixture.route_id(experience.adapter.snapshot(), 0)
await tap("FG2Route_%s" % route_id)
await hold(24)
await tap("FG2DepartButton")
while not experience.battle_result_visible and recording_frames < 620:
experience.advance_battle_ticks(1)
collect_audio_state()
await next_frame()
await hold(32)
if experience.battle_result_visible:
await tap("FG2SettleButton")
await hold(24)
if experience.screen == Controller.SCREEN_REWARD:
await tap("FG2RewardButton")
await hold(36)
collect_audio_state()
experience.configure_entry(Fixture.recovery_market_state())
await hold(48)
if experience.screen == Controller.SCREEN_RECOVERY:
await tap("FG2RecoveryButton")
await hold(48)
collect_audio_state()
while recording_frames < TARGET_CONTENT_FRAMES:
await next_frame()
expect(recording_frames >= MIN_CONTENT_FRAMES and recording_frames <= MAX_CONTENT_FRAMES, "recording stays inside the declared 21.7-30 second window")
expect(experience.screen == Controller.SCREEN_MARKET, "recording ends on a recovered playable Market")
for asset_id in REQUIRED_ASSETS:
expect(heard_assets.has(asset_id), "%s is routed during recording" % asset_id)
for kind in ["route_committed", "wave_arrived", "damage", "fallen", "outcome", "recovery"]:
expect(heard_events.has(kind), "%s event is consumed during recording" % kind)
expect(experience.input_touch_count == parsed_touches and experience.input_drag_count == parsed_drags, "all recording commands remain parsed touch/drag")
expect(experience.fallback_input_count == 0 and experience.direct_command_count == 0, "recording has no fallback or direct player command")
await hold(24)
expect(recording_frames <= MAX_CONTENT_FRAMES, "cleanup hold remains inside 30 seconds")
if failures.is_empty():
print("ABG_FG2_AUDIO_RECORDING_OK frames=%d seconds=%.6f touch=%d drag=%d fallback=0 direct=0 cues=7 events=6 music=true ambience=true terminal=recovered_market" % [recording_frames, float(recording_frames) / 30.0, parsed_touches, parsed_drags])
quit(0)
else:
for failure in failures:
push_error(failure)
quit(1)
func collect_audio_state() -> void:
var state: Dictionary = experience.audio_router.snapshot()
for asset_id in state.asset_play_counts:
if int(state.asset_play_counts[asset_id]) > 0:
heard_assets[String(asset_id)] = true
for kind in state.event_counts:
if int(state.event_counts[kind]) > 0:
heard_events[String(kind)] = true
func tap(node_name: String) -> void:
var control := experience.find_child(node_name, true, false) as Control
expect(control != null, "%s exists" % node_name)
if control == null:
return
var point := root.get_final_transform() * control.get_global_rect().get_center()
var down := InputEventScreenTouch.new()
down.index = 0
down.position = point
down.pressed = true
Input.parse_input_event(down)
parsed_touches += 1
await next_frame()
var up := InputEventScreenTouch.new()
up.index = 0
up.position = point
up.pressed = false
Input.parse_input_event(up)
await hold(4)
func drag(source_name: String, target_name: String) -> void:
var source := experience.find_child(source_name, true, false) as Control
var target := experience.find_child(target_name, true, false) as Control
expect(source != null and target != null, "recording drag targets exist")
if source == null or target == null:
return
var start := root.get_final_transform() * source.get_global_rect().get_center()
var finish := root.get_final_transform() * target.get_global_rect().get_center()
var down := InputEventScreenTouch.new()
down.index = 1
down.position = start
down.pressed = true
Input.parse_input_event(down)
parsed_touches += 1
await next_frame()
for index in range(1, 7):
var motion := InputEventScreenDrag.new()
motion.index = 1
motion.position = start.lerp(finish, float(index) / 6.0)
motion.relative = (finish - start) / 6.0
Input.parse_input_event(motion)
if index == 1:
parsed_drags += 1
await next_frame()
var up := InputEventScreenTouch.new()
up.index = 1
up.position = finish
up.pressed = false
Input.parse_input_event(up)
await hold(4)
func hold(frames: int) -> void:
for _index in range(frames):
collect_audio_state()
await next_frame()
func next_frame() -> void:
recording_frames += 1
await process_frame
func expect(condition: bool, message: String) -> void:
if not condition:
failures.append("FG-2 audio recording: %s" % message)