D401: Rumble Pak -> real gamepad haptics (re-promotes D224/M-87)

Port layer only (zero src/ edits), per docs/dev/RUMBLE-PLAN.md:
- port/src/input.c: inputRumbleSupported/inputRumble -> SDL_GameControllerRumble;
  detection via SDL_GameControllerHasRumble (SDL >= 2.0.18) else
  SDL_JoystickIsHaptic + known-type Windows fallback; zeroed on pad close.
  Single global gRumbleScale (dflt 0.5) registered as Input.RumbleScale.
- port/src/libultra.c: the two M-87 blockers resolved - g_contStatus[i].status
  now sets CONT_CARD_ON for connected rumble-capable pads (so
  joyRumblePakInit arms) and osPfsInit returns PFS_ERR_DEVICE for them (so
  osMotorInit is attempted); osMotorInit/Start/Stop drive the haptics API.
- port/src/optionsoverlay.c: one global 'Rumble strength' ROW_SLIDER
  (Input.RumbleScale, 0.05 detents, %.2f) in the INPUT section +
  kResetDefaults entry. The four per-player Input.PlayerN.RumbleScale keys
  were dropped (user decision 2026-09-28); stale keys in an existing ini
  log four 'unknown key' LOG_NOTE lines and self-clean on next configSave.
- Real-pad haptics confirmed working by the user (2026-09-28).

Build env: build-pc.sh self-heal guard revision - re-exec now writes a
self-contained .ps1 (msys->native argv conversion mangles $-bearing
-Command strings; file write is conversion-free), builds PATH explicitly,
picks TMP from writable candidates (GetTempPath honours the broken
inherited TMP), self-logs to build-pc/ge007-native-reexec-*.log, and
treats a null LASTEXITCODE as 'did not execute' (PS 5.1 piped native
commands error non-terminating). OPEN: the guard still fails inside
build-pc.sh while the identical standalone .ps1 invocation works - AGENTS.md
documents the workaround. docs: RUMBLE-PLAN.md (new, tracked), findings.md
D401 entry + index rows, QOL-INVENTORY D224 -> DONE (D401),
findings-index.csv regenerated.
This commit is contained in:
James Dansereau committed 2026-09-27 23:23:05 -04:00
1 parent a548fc4de6
commit 471eecd6d3
10 files changed
+702 -13

No files matched your search

+47
View File
@@ -39,6 +39,53 @@ Needs CMake + SDL2 + zlib + OpenGL, and must run from the MSYS2 MINGW64 shell
(see `build-pc.sh` header and `docs/building.md`). ROM goes in `./data/`
(not distributed); assets must be extracted from it first (`docs/building.md`).
**Windows build environment (three recurring failure modes — diagnose in this order):**
1. **`Cannot create temporary file in C:\Windows\: Permission denied`** at the
link step. The PE toolchain (ninja → cmd → gcc/ld) needs a writable
TMP/TEMP; the msys→native env conversion drops it in non-login shells
(agent harnesses; the `C:/msys64` tree here was built for `D:/M/msys64`,
so its conversion is unreliable). `build-pc.sh` now **self-heals**: it
probes a native child's TMP (via a file — piped `cmd.exe` stdout is
unreliable under msys console emulation) and, if broken, re-runs
cmake+build under PowerShell with `TMP`/`TEMP` set natively (the
native→native boundary passes env through intact; only msys→native is
broken). If you run cmake/ninja *by hand* from a broken shell: run them
from cmd/PowerShell with `C:\msys64\mingw64\bin` on PATH.
**Guard revision (2026-09-28):** the re-exec writes a self-contained
`.ps1` to a temp file and runs `powershell -File` with plain path/word
args only (the msys→native argv conversion mangles `$`-bearing
`-Command` strings; a file write is conversion-free). Inside: PATH is
built explicitly (never trust the inherited value); TMP is chosen from
writable candidates (`%LocalAppData%\Temp` first —
`[System.IO.Path]::GetTempPath()` honours the inherited *broken* TMP,
observed as `C:\Windows\`); every native step self-logs to
`build-pc/ge007-native-reexec-{diag,cmake,build}.log`; a null
`$LASTEXITCODE` ("did not execute") is a distinct failure (exit 2/3) —
in PS 5.1 a piped native command errors out non-terminating and never
sets it, so an unguarded `if ($LASTEXITCODE -ne 0)` passes vacuously.
In `.ps1`, `-DROMID=$Var` is a literal (bare tokens don't expand) — it
must be `"-DROMID=$Var"`. Launch powershell plainly — `env -i` before it
breaks the nested cmake launch (verified 2026-09-28).
**OPEN (next session):** the guard still fails *inside* `build-pc.sh`
(cmake "did not execute": the `.ps1` runs, but `$LASTEXITCODE` stays
empty) while the *identical* standalone invocation succeeds (cmake runs
and the build completes — that is how the D401 builds were made). First
test: diff the heredoc-generated `.ps1` against a hand-extracted copy
(suspect: heredoc line-ending/whitespace corruption).
**Working workaround:** extract the heredoc `.ps1` and run
`powershell -NoProfile -ExecutionPolicy Bypass -File <ps1> "C:\msys64\usr\bin" "C:\msys64\mingw64\bin" C:/msys64 <repo-win-path> build-pc <romid>`.
2. **`cannot open output file ge007.x86_64.exe: Permission denied`.** A
**running** `ge007.x86_64.exe` locks the output file (Windows rule; you
can't relink over a live PE). Check with `Get-Process | Where-Object {
$_.ProcessName -like '*ge007*' }` and close the game before rebuilding.
An agent must not kill the user's game process to make a link succeed.
3. **`cc1.exe: ... libmpfr-6.dll: cannot open shared object file`.** The
calling PATH lacks `C:\msys64\mingw64\bin` (the gcc driver finds cc1 via
its own directory, but the child needs the mingw DLL dir on PATH). In an
msys shell: `export PATH="/c/msys64/mingw64/bin:/c/msys64/usr/bin:$PATH"`
before building.
## Verification ritual (after any build-affecting change)
1. **Undefined symbols.** Every symbol referenced by the compiled set (see `CMakeLists.txt`: `SRC_GAME`, `SRC_ENGINE`, `SRC_LIBAUDIO`, `SRC_LIBULTRARE_AUDIO`, `SRC_LIBULTRARE_DATA`, `SRC_GU`, `SRC_PORT*`) must be defined exactly once in the compiled set or in `port/`. Symbols that live in EXCLUDED files (`libultra/io/*`, `libultrare/io/*` except `vitbl.c`, `libultra/os/*`, `libultrare/os/*`, `sched.c`, `rmon.c`, `vi.c`, `src/*.s`) must be provided by `port/src/libultra.c`, `gesched.c`, `n64stubs.c`, `random.c`, or `ucode.c`.