pod: bundled per-game deployment (portable config, --exit-with, build-pod)
Phase 10: RIO hardware exists only on pods + dev boxes, so production is one RIOJoy copy inside each podized game folder, no resident tray. ConfigLocator makes a config.json beside the exe win over %APPDATA%; --exit-with <exe|pid> (CompanionTarget/CompanionExit, 60s startup grace) tears down and quits when the game exits; a starting --exit-with instance waits up to 15s for the predecessor mutex instead of silently exiting. deploy/build-pod.ps1 emits the ~4.5MB drop-in (app + portable config wrapping the profile + start script, no drivers) - verified against the shipped Descent profile. 455 tests; PLAN.md Phase 10 + INPUT-INTEGRATION.md pod section. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -141,6 +141,14 @@ example: throttle → `RightThumbY` `UnipolarPositive`, rudder mix →
|
||||
|
||||
## Shipping a profile with your game
|
||||
|
||||
Two models, chosen per deployment:
|
||||
|
||||
- **Pod bundle (production — cockpit cabinets):** the game's folder carries
|
||||
its own RIOJoy copy + profile; nothing is registered anywhere. See
|
||||
[Pod-bundled deployment](#pod-bundled-deployment-production) below.
|
||||
- **Import into a resident RIOJoy (dev boxes):** hand a profile document to
|
||||
the shared tray install, as follows.
|
||||
|
||||
A game (or its installer/launcher) hands its profile to RIOJoy as a
|
||||
**single-profile JSON document** plus one command:
|
||||
|
||||
@@ -186,6 +194,40 @@ repo as the source of truth — dxx-rebirth does this, and a RIOJoy test
|
||||
(`ShippedDescentProfile_MatchesDxxRebirthReferenceCopy`) asserts the two
|
||||
checkouts stay byte-identical so drift is caught in CI.
|
||||
|
||||
## Pod-bundled deployment (production)
|
||||
|
||||
On the pods (the cockpit cabinets) no resident RIOJoy runs at all. Each
|
||||
podized game's install carries its own copy, built by:
|
||||
|
||||
```
|
||||
deploy\build-pod.ps1 -ProfileJson <your-game-profile.json>
|
||||
```
|
||||
|
||||
That emits a ~5 MB drop-in — `riojoy\` (app + a **portable** `config.json`
|
||||
holding just this game's profile; a config beside the exe wins over the
|
||||
per-user `%APPDATA%` store) plus `start-riojoy.bat` — which the game's
|
||||
launch script calls before starting the game:
|
||||
|
||||
```
|
||||
start "" "...\riojoy\RioJoy.Tray.exe" --exit-with <game exe>
|
||||
```
|
||||
|
||||
`--exit-with` makes RIOJoy self-managing: it activates when the game's window
|
||||
comes foreground, and once the game process has run and then exited it tears
|
||||
itself down completely (ports released, wallpaper restored, plasma blanked)
|
||||
and quits. If the game never appears within 60 s it also quits, so a failed
|
||||
launch can't strand it. Back-to-back launches hand over cleanly: a starting
|
||||
`--exit-with` instance waits up to 15 s for the previous game's copy to
|
||||
release the single-instance lock.
|
||||
|
||||
Properties that matter on a cabinet: each game pins the RIOJoy build it was
|
||||
verified with (updating RIOJoy for a new game can't regress an old one);
|
||||
native games simply don't bundle RIOJoy, so the COM ports are free for them
|
||||
by construction; and drivers stay a one-time pod provisioning step (the
|
||||
universal package's `install-rio.ps1`) — pod bundles deliberately carry none.
|
||||
The bundled exe is still the full tray app: run it with no arguments on the
|
||||
pod and you have the profile editor.
|
||||
|
||||
## Testing without hardware or game
|
||||
|
||||
- **vRIO** (`pipe:vrio`): click buttons on the emulator's panel and watch them
|
||||
|
||||
@@ -490,6 +490,45 @@ spec + client snippets in [`docs/FEEDBACK.md`](FEEDBACK.md). Delivers the
|
||||
settings (JSON-only today); shipped client examples (SimHub plugin / DCS
|
||||
export script) beyond the FEEDBACK.md snippets.
|
||||
|
||||
### Phase 10 — Pod-bundled deployment — code-complete ✅
|
||||
Deployment topology decision (2026-07-31): RIO hardware exists only on **pods**
|
||||
(the cockpit cabinets) and dev boxes — no freestanding end-user PCs. Production
|
||||
model is therefore **one RIOJoy copy bundled inside each podized game's
|
||||
folder**, started by the game's launch script and exiting with the game; no
|
||||
resident RIOJoy runs on a pod, and the native games simply don't bundle one
|
||||
(making the COM-port yield machinery vestigial in production). The resident
|
||||
tray + auto-switch reclassifies as the development harness. 455 xUnit tests
|
||||
total across the suite.
|
||||
- **Portable config**: `ConfigLocator.Resolve` — a `config.json` beside the
|
||||
exe wins over `%APPDATA%\RIOJoy\config.json`; `TrayApplicationContext.
|
||||
ConfigPath` resolves through it, so `--import-profile` targets the same
|
||||
store. A pod bundle needs no import step: its config *is* the profile.
|
||||
- **`--exit-with <exe|pid>`** (`CompanionTarget.Parse` — pid, or a name
|
||||
normalized like auto-switch triggers): the tray polls the companion on its
|
||||
existing 1 s timer and quits through the normal teardown (ports released,
|
||||
wallpaper restored, plasma blanked) once the game has run and then gone.
|
||||
`CompanionExit` holds the pure decision — launch order isn't guaranteed, so
|
||||
a never-seen companion only triggers exit after a 60 s startup grace
|
||||
(also covers "game failed to launch"). Clock-free and unit-tested
|
||||
(`tests/.../Hosting/CompanionExitTests`).
|
||||
- **Instance handoff**: with `--exit-with`, a starting instance waits up to
|
||||
15 s for the predecessor's single-instance mutex (game A's copy tearing
|
||||
down while game B's starts) instead of the historical silent exit-0; plain
|
||||
launches keep the instant-exit behavior. Abandoned mutex (predecessor
|
||||
crash) counts as acquired.
|
||||
- **`deploy/build-pod.ps1`**: emits the per-game drop-in — `riojoy\` app
|
||||
(flavor-selectable net48/net40, Skia-pruned) + portable `config.json`
|
||||
wrapping the game's profile document verbatim + `start-riojoy.bat`
|
||||
(`--exit-with` prefilled from the profile's first trigger) + README-POD —
|
||||
zipped as `RIOJoy-pod-<name>-<stamp>.zip` (~4.5 MB). Deliberately **no
|
||||
drivers**: pods are provisioned once by the universal package. Verified by
|
||||
building the Descent bundle and round-tripping its emitted config through
|
||||
`ConfigStore.Load`.
|
||||
- ⏳ **Remaining:** on-pod verification of the full launch/handoff cycle
|
||||
(launcher → game A → quit → game B); podize a first real game with the
|
||||
bundle; revisit the universal zip's `install.bat` framing (dev-setup only)
|
||||
once pod deploys are routine.
|
||||
|
||||
---
|
||||
|
||||
## Open items / risks
|
||||
|
||||
Reference in New Issue
Block a user