Control the xemu Xbox emulator for SSX 3 reference comparisons - boot it with the ISO, restore saved snapshots (character select, race briefing, race start) in about a second, press controller buttons, pause/resume and take lossless screenshots without stealing the user's focus. Use whenever our recompiled build's output needs checking against real Xbox behaviour (lighting, colours, geometry, menus, race scenes).
Install
npx skillscat add koenhendriks/ssx3-recomp/xemu Install via the SkillsCat registry.
xemu control (SSX 3 reference)
Everything goes through tools\xemu.ps1 in the ssx3-recomp repo (Windows
side). From WSL:
cd /mnt/c/Code/Xbox/ssx3-recomp
X() { powershell.exe -NoProfile -ExecutionPolicy Bypass -File tools\\xemu.ps1 "$@"; }
X start -Snapshot race_go -Paused # boot + restore a state: ~2.5 s
X cap -Out 'C:\Code\Xbox\ssx3-recomp\shots\xemu\race.png'
X stopAfter editing the script in WSL run scripts/sync-windows.sh first (the
Windows copy is what runs).
Commands
| Command | What |
|---|---|
start [-Snapshot tag [-Paused]] [-Iso p] [-Exe p] [-Audio] [-Pad] [-Port 4455] |
Boot our own instance (see below). With -Snapshot it restores that state right away; -Pad also binds the user's own gamepad (port 2) for when they play in it. |
stop |
Quit our instance (QMP quit, then its PID). Never kills other xemu processes. |
status |
Our instance (pid, run state) and any user xemu. |
cap [-Out file] [-Target ours|user] |
Screenshot of the client area (1280x960 = 2x our 640x480), PrintWindow: no focus change, works when covered, not when minimised. Default target: ours if running, else the user's. |
press -Keys "..." [-Target ours|user] [-Gap 250] |
Button steps, comma-separated: a, start:300 (hold ms), a+down:500 (together), wait:2000. |
pause / resume |
Freeze / continue the emulated machine (QMP stop/cont). |
save -Name t / load -Name t [-Paused] / delete -Name t / snapshots |
VM snapshots (~1 s each way, ~55 MB, inside our HDD copy). |
hmp -Cmd "..." / qmp -Cmd '{...}' |
Raw monitor access (e.g. hmp -Cmd "info status"). |
Buttons (xemu's default keyboard map): a b x y up down left right start back white black lt rt ls rs lsup lsdown lsleft lsright rsup rsdown rsleft rsright.
Our instance vs the user's xemu
start launches a separate xemu: config work\xemu\xemu.toml (regenerated
each start), its own copies of the user's HDD image and EEPROM inwork\xemu\, **muted** (pass -Audio only if sound is needed and the user is
around), only the keyboard bound (the user's real pad never reaches it), no
shader cache (that cache is shared with the user's xemu), QMP on
127.0.0.1:4455. It runs fine next to the user's own xemu. Key presses are
posted window messages: SDL reads them without focus, so the user's keyboard
focus is never taken (start also hands focus back after the window opens).
- Never
pressinto the user's xemu (-Target user) unless they asked for
it;cap -Target useris harmless. stopour instance when done; restarting from a snapshot is ~2.5 s.- Snapshots belong to the ISO + HDD copy they were made with. Deleting
work\xemu\xbox_hdd.qcow2deletes all snapshots.
Snapshots (SSX 3 PAL, Griff, Snow Jam race)
| Tag | State |
|---|---|
unlocked_main |
Main Menu, the user's save with everything unlocked (cheat) loaded |
unlocked_charsel |
Select Character (Griff highlighted) from that save |
race_briefing |
Snow Jam race briefing -- made BEFORE the cheat save |
race_go |
Snow Jam race start, "GO!" -- made BEFORE the cheat save |
intimidator_brief |
Peak 2 Intimidator race briefing (Griff) |
launchtime_brief |
Peak 2 Freestyle "Launch Time" (Big Air) briefing |
metro_brief |
Metro-City race briefing (Griff) |
Snapshots include the hard disk: loading race_* rolls the HDD copy back to
before the user's cheat save. Make new snapshots only after loading anunlocked_* one. Snapshots made with -Pad (extra USB hub) load only with-Pad, and vice versa -- keep making them without it.
Peak page: the list reads Peak 3, Peak 2, Peak 1 with the cursor on Peak 1
(Up = next peak; Down wraps to Peak 3). Race events: Peak 1 Snow Jam,
Metro-City, Happiness; Peak 2 Ruthless Ridge, Intimidator, Ruthless; Peak 3
Gravitude, The Throne. From unlocked_charsel: a (rider), a (setup),up x(peak-1), a, a (Race; down for Freestyle), down x event, a,a (rules) -> loading.
A load restores a stale picture for the first frames; -Paused runs 150 ms
(-SettleMs) before freezing, so the captured frame is current. Check what
exists with X snapshots.
Recreating them from a cold boot (X start, fresh save, ~2.5 min):
- Wait ~20 s (EA/intro movies),
press -Keys "start,wait:3000"until the
title shows "Press START", thenstart:200-> Main Menu (fades in ~1.5 s). a:200(Single Event) -> Select Character. On a fresh save the default
rider is one left of Griff (3xrightlanded on Elise, 2xleftback on
Griff) -- step withleft/rightandcapto read the name under the
silhouettes.save -Name charsel_griff.a:200,wait:3000,a:200,wait:3000,a:200,wait:3000(Griff, Continue,
Peak 1) -> Select Mode;a:200,wait:3000,a:200,wait:3000(Race, Snow Jam)
-> My Rules;a:200,wait:25000-> briefing.save -Name race_briefing.a:200,wait:2500,pause,capto check for "GO!",save -Name race_go.
Start during the race intro opens the pause menu (Return/Restart/Audio/
Options/Quit); start again resumes.
Frame rate in xemu
tools\xemu_fps.ps1 [-Seconds N] [-Tap] prints rendered frames per second,
read from SSX 3's renderer frame counter ([0x369528]+0x771C) through the
monitor (hmp -Cmd "x/1wx <va>" reads any guest virtual address). xemu
itself runs a little under 60 in places, so compare shapes (a halving), not
absolute numbers. Example: Metro-City drops to exactly 30 in its tunnel
section in xemu and in our build alike.
Comparing with our build
Our side: tools\menu_test.ps1 -Steps 'start,wait,right,wait,right,wait,right,wait,wait' -ShotDir shots\griff
(Select Character, Griff) or tools\race_test.ps1 -Runs 1 -RaceSec 5 -NoTaps -Rider 3 -Snap shots\race.png
(Snow Jam as Griff). Our frames are 640x480, xemu's 1280x960: compare at
the same scale. Timing never matches to the frame (animation, AI riders), so
compare materials/lighting/colour, not exact poses.