Trying to read a third paint order off the running game turned up two bugs in the capture harness, both of which fail in ways that look like the game misbehaving rather than the script being wrong. 1. `--audio` is not a cvar in this tree, and eight boot scripts passed it. Xenia calls ShowSimpleMessageBox from ParseLaunchArguments, BEFORE logging is initialised, so the symptom is a 10x10 window, no log, no guest memory and a dialog that blocks on XIfEvent forever - i.e. a hang deep in the emulator. run-canary`s own header documents this exact trap; the scripts predate it. Removed from all eight. 2. `vgamepad` no longer exists - the uinput pad was replaced by the --hid=file driver and pad.py - but skip_intro.sh still called it. The script runs without `set -e`, so the call failed silently and the title branch pressed nothing while still exiting 0. A caller was told "TITLE -> A" with the game sitting on the title screen. It now presses through pad.py and exits 6 if that fails. The first bug is fixed and verified: the boot now reaches the title screen with PRESS (A) BUTTON. The second is fixed but does NOT unblock the title - see the next commit.
56 lines
3.0 KiB
Bash
Executable File
56 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Drive the boot sequence to the main menu without a human in the loop.
|
|
# - movie playing (two grabs 0.6s apart differ a lot) -> tap A to skip
|
|
# - static screen -> if the green "PRESS (A) BUTTON" glyph is there, tap A and stop
|
|
# Static logo screens are left alone, so a stray tap can never land on NEW GAME.
|
|
#
|
|
# LIVENESS IS CHECKED EVERY ITERATION, and that is not a nicety. When the
|
|
# display died 3 minutes into a run, `screenshot` started failing silently and
|
|
# left /tmp/f1.png and /tmp/f2.png at their last contents — two *stale* files,
|
|
# which compare to a constant non-zero RMSE, which reads exactly like "the
|
|
# screen is changing a lot". So the loop reported "movie -> skip A" every 5 s
|
|
# for the full 600 s timeout with no emulator and no X server running. A dead
|
|
# display and a playing movie must never be able to look the same.
|
|
set -u
|
|
export HOME=/sylph-home/re
|
|
DISP="${DISPLAY:-:98}"
|
|
alive(){ ps -o pid=,stat= -C xenia_canary 2>/dev/null | awk '$2 !~ /^Z/ {print $1}'; }
|
|
# Press through pad.py, NOT `vgamepad`. That command no longer exists — the
|
|
# uinput pad was replaced by the `--hid=file` driver — and because this script
|
|
# runs without `set -e`, calling it failed silently: the title branch pressed
|
|
# nothing and still `exit 0`, so a caller was told "TITLE -> A" while the game
|
|
# sat on the title screen forever. Fail loudly instead.
|
|
SD_SI="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
tapA(){ python3 "$SD_SI/pad.py" tap A 0.25 || { echo "PAD PRESS FAILED"; exit 6; }; }
|
|
# The X root keeps the DEAD session's last frame, so a fresh launch would be
|
|
# detected as "already at the title". Blank it, and wait for the new window.
|
|
xsetroot -solid black 2>/dev/null || true
|
|
until xdotool search --name "Xenia-canary" >/dev/null 2>&1; do
|
|
xdpyinfo -display "$DISP" >/dev/null 2>&1 || { echo "DISPLAY LOST at ${SECONDS}s (before the window appeared)"; exit 3; }
|
|
[ -n "$(alive)" ] || { echo "EMULATOR GONE at ${SECONDS}s (before the window appeared)"; exit 4; }
|
|
sleep 1
|
|
done
|
|
deadline=$(( SECONDS + ${1:-900} ))
|
|
while [ $SECONDS -lt $deadline ]; do
|
|
rm -f /tmp/f1.png /tmp/f2.png
|
|
screenshot /tmp/f1.png >/dev/null 2>&1; sleep 0.6
|
|
screenshot /tmp/f2.png >/dev/null 2>&1
|
|
if [ ! -s /tmp/f1.png ] || [ ! -s /tmp/f2.png ]; then
|
|
xdpyinfo -display "$DISP" >/dev/null 2>&1 \
|
|
|| { echo "DISPLAY LOST at ${SECONDS}s"; exit 3; }
|
|
echo "SCREENSHOT FAILED at ${SECONDS}s with the display up"; exit 5
|
|
fi
|
|
[ -n "$(alive)" ] || { echo "EMULATOR GONE at ${SECONDS}s"; exit 4; }
|
|
d=$(compare -metric RMSE /tmp/f1.png /tmp/f2.png null: 2>&1 | sed 's/ .*//' | cut -d. -f1)
|
|
d=${d:-0}
|
|
read -r r g b < <(convert /tmp/f2.png -format "%[fx:int(255*p{625,618}.r)] %[fx:int(255*p{625,618}.g)] %[fx:int(255*p{625,618}.b)]" info:)
|
|
if [ "$g" -gt 130 ] && [ $((g - r)) -gt 45 ] && [ $((g - b)) -gt 45 ]; then
|
|
echo "TITLE at ${SECONDS}s -> A"; tapA; exit 0
|
|
fi
|
|
if [ "$d" -gt 1500 ]; then
|
|
echo "movie (rmse $d) at ${SECONDS}s -> skip A"; tapA; sleep 3
|
|
fi
|
|
sleep 1
|
|
done
|
|
echo "TIMEOUT"; exit 1
|