feat: multi-game port selection — the machine says which game it is on
The runtime tried one port file (game.port) and refused it if the game's words did not match. Now it tries every *.port in /usr/local/padmode/ports and /dump/ports (then the single files, the old layout), resetting the port tables between candidates, and keeps the first whose core sites verify: a wrong candidate hooks nothing, so trying it is safe, and the port that verifies names the game (pm_game/pm_version). The switch log's buttons and names come from the port's switch lines now — the baked-in King Kong button list and switch_names.inc are gone (the port lines carry the same ids and names, so King Kong's switch.log is unchanged). Boot log: each refused candidate says its path and the game/version it declares; no candidates at all says so; a game update whose port is not deployed logs the refusal and runs stock. tests/test_multi_game.py lifts the new code verbatim and compiles it for the host: selection among candidates, table reset between them, the getdents64 *.port scan (it caught an inverted suffix test and an off-by-one), and the port-driven switch log. The address-dependent tests need a Linux host (the port's site addresses are 32 bits; darwin arm64 maps nothing below 4 GiB). Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -33,12 +33,37 @@ framework) and added to `ports/king_kong_le-0.97.port`.
|
||||
| File | What it is |
|
||||
|---|---|
|
||||
| `gamelog.c` | the logger: a passive PAD mode. It never `pm_begin()s`, never blocks, allocates nothing — it only watches and writes `[GAMELOG]` lines |
|
||||
| `pad_mode_runtime.c` | the PAD Modes SDK runtime, **patched**: (a) a GAMELOG section — passive stock-mode and award watching, exporting `gl_award_seq()` / `gl_last_award_id()` to modes; (b) the per-edge switch logger to `/dump/switch.log`; (c) the Insider Connected gate made passive. Our exact changes vs upstream: `docs/runtime-patch.diff` |
|
||||
| `switch_names.inc` | King Kong LE 0.97 switch id → name table (104 entries, ids 1–104), `#include`d by the runtime's switch logger. Generated from the game's own data (method: `swnames.py` in the decryptor repo); fix names here if any are wrong |
|
||||
| `pad_mode_runtime.c` | the PAD Modes SDK runtime, **patched**: (a) a GAMELOG section — passive stock-mode and award watching, exporting `gl_award_seq()` / `gl_last_award_id()` to modes; (b) the per-edge switch logger to `/dump/switch.log`, named by the port's `switch` lines; (c) the Insider Connected gate made passive; (d) multi-game port selection (`port_select` — below). Our exact changes vs upstream: `docs/runtime-patch.diff` |
|
||||
| `pad_mode.h`, `pad_stock.h` | unmodified SDK headers (needed by the build) |
|
||||
| `build_mode.sh` | unmodified SDK build script: compiles the runtime + your mode into one `-nostdlib` shared object and refuses banned libc calls |
|
||||
| `event_probe.c`, `event_read.py` | the event-bus measurement instrument and its log reader — how bus event ids are identified for another game (MODE_SDK.md, "Measuring events on another game") |
|
||||
| `ports/king_kong_le-0.97.port` | the King Kong LE 0.97 port: 121 verified sites, 55 named shots, 6 bus events. Installed on the machine as `/usr/local/padmode/game.port` |
|
||||
| `tests/test_multi_game.py` | host-compiled tests for the port selection, the ports-directory scan and the switch log (they lift the runtime's own code verbatim; the address-dependent ones need Linux — run them in the Debian container below) |
|
||||
| `ports/king_kong_le-0.97.port` | the King Kong LE 0.97 port: 121 verified sites, 55 named shots, 6 bus events. Installed on the machine as `/usr/local/padmode/ports/king_kong_le-0.97.port` |
|
||||
|
||||
## Multiple games
|
||||
|
||||
One `mode.so` runs on any game that has a port. The machine says which game it is
|
||||
on by which port's sites verify — the runtime tries every candidate in order and
|
||||
keeps the first whose core functions match the running build's instruction words
|
||||
(the same gate that keeps a wrong port from hooking anything):
|
||||
|
||||
1. every `*.port` in `/usr/local/padmode/ports/` and `/dump/ports/` (name order
|
||||
is the directory's; only the right build's port can verify, so the order
|
||||
does not matter), then
|
||||
2. the single files `/usr/local/padmode/game.port` and `/dump/game.port`, the
|
||||
old one-game layout.
|
||||
|
||||
The boot log says what happened:
|
||||
|
||||
```
|
||||
[pad] port /usr/local/padmode/ports/godzilla_le-1.16.port: says godzilla_le 1.16 - not this game's port, skipped
|
||||
[pad] port /usr/local/padmode/ports/king_kong_le-0.97.port: king_kong_le 0.97, 121 sites, 55 shots
|
||||
```
|
||||
|
||||
A game update changes the words, so its old port stops matching — the machine
|
||||
logs the refusal and runs stock until the new game version's port is deployed.
|
||||
The switch log's buttons and their names come from the port's `switch` lines;
|
||||
a port that names none logs no switch edges.
|
||||
| `docs/runtime-patch.diff` | this project's changes to the upstream runtime (base: `pinball-asset-decryptor` commit `7faf8f08`, the last upstream change to that file) |
|
||||
|
||||
## What gets logged
|
||||
@@ -100,9 +125,9 @@ the main flipper buttons on this cabinet, so they are left out:
|
||||
```
|
||||
|
||||
`level` is the switch's raw state after the edge, `hit` is the game's own
|
||||
"counts as a hit" verdict, `game` whether a player is up. The logged ids are
|
||||
the `gl_buttons[]` list in the runtime's switch-edge handler; names come from
|
||||
`switch_names.inc`.
|
||||
"counts as a hit" verdict, `game` whether a player is up. The logged ids and
|
||||
names are the port's `switch` lines (on King Kong: 34 lockdown, 36 start,
|
||||
62/63 the flipper buttons).
|
||||
|
||||
## Build
|
||||
|
||||
@@ -123,6 +148,15 @@ from the game's own libc when the object loads.
|
||||
The event probe builds without the runtime:
|
||||
`build_mode.sh -p -o event_probe.so event_probe.c`
|
||||
|
||||
The port-selection tests run on any Linux host (the address-dependent ones skip
|
||||
on macOS, whose arm64 maps nothing below 4 GiB):
|
||||
|
||||
```bash
|
||||
docker run --rm --platform linux/arm64 -v "$PWD:/work" -w /work debian:12 \
|
||||
sh -c 'apt-get update -qq && apt-get install -y -qq python3 python3-pytest gcc >/dev/null \
|
||||
&& python3 -m pytest tests/test_multi_game.py -q'
|
||||
```
|
||||
|
||||
## Install / deploy (the machine)
|
||||
|
||||
The machine (hostname `stern-spike2`) has root SSH (key-only, port 22). The
|
||||
@@ -131,7 +165,7 @@ logger lives on the rootfs, which is normally read-only:
|
||||
| Path on the machine | From this repo |
|
||||
|---|---|
|
||||
| `/usr/local/padmode/mode.so` | the built `mode.so` |
|
||||
| `/usr/local/padmode/game.port` | `ports/king_kong_le-0.97.port` |
|
||||
| `/usr/local/padmode/ports/king_kong_le-0.97.port` | `ports/king_kong_le-0.97.port` (one file per game; see "Multiple games") |
|
||||
| `/etc/init.d/game_monitor` | boot hook: preloads `mode.so` into the game **only if it exists** (stock script kept at `game_monitor.stock`) |
|
||||
|
||||
Deploy a new build:
|
||||
@@ -200,8 +234,8 @@ Built on the PAD Modes SDK
|
||||
Everything in this repo is unmodified SDK content except:
|
||||
|
||||
- `gamelog.c` (new)
|
||||
- `switch_names.inc` (new)
|
||||
- `pad_mode_runtime.c` (upstream runtime + the patch in `docs/runtime-patch.diff`)
|
||||
- `tests/test_multi_game.py` (new)
|
||||
- `README.md`
|
||||
|
||||
`ports/king_kong_le-0.97.port`, `event_probe.c`, `event_read.py`,
|
||||
|
||||
Reference in New Issue
Block a user