Files
llamamod/notes/testharness.md

8.2 KiB
Raw Permalink Blame History

Test harness tools/lamatest.py

Starts "Ein Königreich für ein Lama" unattended and invisibly (Xvfb :5, sound into a null sink), loads TestLevel chapter 1 (T1L9M001.wad) and takes screenshots. Tested on 2026-11-06 with Wine 6.0.3, llvmpipe.

Commands

lamatest.py run <wad> <outdir> [n]   # all in one: install, start, tolevel, tour, stop
lamatest.py start                    # Xvfb :5 + null sink lama_stumm + groove.exe
lamatest.py tolevel                  # menu -> slot with TestLevel -> chapter 1 -> gameplay
lamatest.py tour <outdir> [n]        # n camera shots (look around) + n walking shots + llama view
lamatest.py shot out.png             # full screen 1920x1080
lamatest.py key <xdotool-key> [s]    # hold key for s seconds (default 0.12)
lamatest.py keys Up:1.5 a:0.5 x      # sequence, name[:hold time], also sleep=2
lamatest.py seq <outdir> "TOKENS"    # --seq tokens (shot:, run:, rj: …) in the running game
lamatest.py status | stop | restore-wad

run options (added 2026-11-06)

lamatest.py run <wad> <outdir> [n] [--seq "TOKENS"] [--tour] [--keep]
  • WAD restore: run remembers the previously installed T1L9M001.wad ($LAMATEST_DIR/vorher_T1L9M001.wad) and restores it after the run – i.e. not .orig. With --keep the tested WAD stays installed. (restore-wad still explicitly restores .orig.)

  • --seq replaces the default tour with a key sequence (with --tour the tour runs as well):

    • Up:1.5, a:0.5, x … key[:hold time] as with keys; sleep=1
    • shot:NAME → seq_NN_NAME.jpg, fp:NAME → shot in llama view (Return held)
    • dialog → click away dialog/letterbox
    • Up+x:0.8 → hold keys simultaneously
    • rj:T1:T2 → running jump (hold Up, X after T1 s, Up for another T2 s)
    • dj:T → double X with run-up, hop:N:T → hold Up, jump N× every T s
    • run:T:x@1.3,x@2.9,shot@5.0,Left@3.0-3.4 → hold Up for T s, following a schedule (s from start) tap X / take a shot (seq_NN_runT.jpg) / hold a key from–to; run/Left:T:… holds another key instead of Up. Real time: a shot blocks ~0.4 s (delays subsequent events and slows the game down) → no shots shortly before jumps.
  • Controls are camera-relative (Up = in the camera's view direction, Left/Right sideways). A/S rotate the camera, S:0.45 ≈ look 90° to the left.

  • Measurements (llama): ~1.1 units/s walking, jump 0.35 high, ~1.3 far with run-up – see levelbau.md. Timed runs scatter by ~0.3 units (start delay, frame rate); longer distances need "stops" (a wall/step where the llama comes to a halt).

  • Camera: after running into a wall or a fall the camera rotates unpredictably → Up then walks in a different direction. A/S rotation (S:0.45) is only roughly 90°.

  • Complete test world parkour as a script: levels/testwelt_parkour.seq (levelbau.md).

  • LAMATEST_SHOT=1280 (environment): shot:/fp: shots at 1280×720, quality 85 instead of 960×540 (preview images).

  • "EINGEFROREN?" (frozen?) for a --seq without movement (e.g. only sleep=3 shot:x) is a false alarm – the standing llama does not change the image; with camera rotation/walking you get "OK".

  • Good viewing angles in the game are hard: the camera hangs low behind the llama; elevated start points (pedestal, parkour checkpoint pk2 + A:0.6) show several areas.

Helper script for series: $CLAUDE_JOB_DIR/tmp/lb_run.sh WAD NAME "SEQ" (montage lb_mNAME.jpg, WAD path absolute!), rs.sh NAME "SEQ" (restart with installed WAD + seq, montage i/NAME.jpg). Caution: no pgrep -f groove.exe in wait loops – it matches your own shell (the command line contains "groove.exe") and lamatest takes it for a foreign instance.

State/PIDs/wine.log: $LAMATEST_DIR (default /tmp/lamatest-$USER). Game: $LAMA_WINEPREFIX (default ~/.wine-lama), lama-mod: $LAMA_MOD (see docs/tools.md).

run exit codes: 0 OK, 3 crash, 4 timeout/hang, 5 image frozen. Output in <outdir>: report.txt, wine.log (stderr, truncated to 2 MB), 00_geladen.png (full) + .jpg, tour_*.jpg (960x540, ~30 KB), on failure zz_absturz.jpg / zz_timeout.jpg. One run ≈ 75 s, ≈ 1.2 MB.

Safety rules (implemented in the script)

  • Aborts if a groove.exe with a different DISPLAY is running (the user's own instance).
  • xdotool only with DISPLAY=:5.
  • Sound: own null sink, the app is never muted; stop unloads the sink.
  • Save games (*.ksv in the game folder) are backed up on start and restored on stop if changed (newly created ones are deleted).
  • stop: wineserver -k only if no foreign groove.exe is running, otherwise only own PIDs.
  • The test world exit saves progress (chapter 2 unlocked) – restored on stop together with the save games.
  • WAD: the first run backs up the original as mods/testlevel/wads/T1L9M001.wad.orig; restore-wad restores it. The overlay (lama-mod an) consists of symlinks to the mod files → overwriting ~/.wine-lama/mods/testlevel/wads/T1L9M001.wad takes effect immediately; lama-mod an is only called if the overlay link is missing.

tolevel sequence (measured)

Step Key Detection t (from start)
Logo → main menu – OCR crop 700x300+1150+650, threshold 75 % → only the highlighted item "Spiel starten" is readable ~6 s
"Spiel starten" (start game) Return –
Save slot selection (carousel, starts at slot 2, no wrap) Left ×3, then Right until "TestLevel" OCR crop 1600x280+160+740 (fuzzy, 2 thresholds) ~20 s
Load slot 3 Return selection map = >75 % beige pixels ~25 s
Activate chapter 1 (cursor from KSV +4/+5) Return
Camera fly-through (letterbox: top+bottom row black) Return skips +1.5 s
Gameplay – bright, no letterbox, golden HUD top left (or >25 s) 3× in a row ~29 s total, loading ~4 s

Without skipping, the camera fly-through in the village takes ~20 s. Loading screen = T191.COR ("TestLevel Kapitel 1 … LADEVORGANG").

Fallback: if no menu is detected, Return after 40 s (skips the demo). Caution: Return on a misdetected screen can start a different game – but save games are restored at the end.

PC controls (keyboard, from "Optionen → Tastatur konfigurieren", verified)

Action Key
Up / Down (walk forward / backward) Up / Down
Left / Right (turn) Left / Right
Jump (also advances dialog) X
Action Z
Power Space
Llama view (first person, hold) Return
Rotate camera left / right A / S (hold 0.5 s ≈ 90°)
Pause menu Escape

Registry HKCU\Software\Disney Interactive\Emperors New Groove\1.0, "InputDevice Wine Keyboard" = 14 DIK codes (4 hex digits each): CB Left, CD Right, C8 Up, D0 Down, 1E A, 1F S, 39 Space, 2D X, 1C Return, 19 P, C9 PgUp, D1 PgDn, 2C Z, 18 O. The registry order ≠ menu order; P/PgUp/PgDn/O probably pause/inventory (according to exe strings: PAUSE GAME, CYCLE INVENTORY UP/DOWN, USE AN ITEM, TURN 180, SELECT) – not verified. Other values there: CameraMode, ControlType, ScreenW/H (1920x1142), CDPath=L:.

Pause menu (Escape): graphics/sound options, configure keyboard/joystick, more options, continue, "Beenden und zur Auswahlkarte wechseln" (quit to selection map; confirmation Ja/Nein, default Nein → Up, Return), quit game. Main menu submenus: Escape = back.

Observations on the village 1 copy

  • Walking forward in the village immediately starts the Pacha dialog (letterbox with subtitles, ~9× X to click through). tour detects this, photographs the dialog once and clicks it away.
  • The llama can fall off the cliff during the tour (respawn) – irrelevant for visual checks.

Crash detection

Per poll: groove.exe process on :5 gone / window "Groove" gone / window with "Programmfehler", "error", "exception" … (Wine crash dialog). The report contains the line wine: Unhandled page fault … at address XXXXXXXX (look up the address in Ghidra). Tested: WAD truncated to 300 KB and WAD with 2000 random bytes → both crash during the loading screen, detected after ~5 s (exit 3). Harmless log noise (gstreamer/MPEG-1 missing, ole, ChangeDisplaySettings, MIDIMAP) is filtered out of the report.

Dependencies

Xvfb, xdotool, ImageMagick (import/convert), tesseract with deu, pactl, wine.