Specs everything a game team needs to deploy and command a title in a Tesla pod bay: package zip + Apps.xml catalog contract, launch/watchdog semantics, the full Munga wire spec (framing, message set, state machine, egg envelope), the dedicated game-console escape hatch, the modern bay address plan, LC/MR presentation roles, score-sheet printing, and RIO board integration (native preferred over the RIOJoy shim). XP support is documented as a nice-to-have for new games; the floor remains suite-side. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
511 lines
26 KiB
Markdown
511 lines
26 KiB
Markdown
# Deploying and commanding a game in a Tesla pod bay
|
||
|
||
**Audience:** developers of games being brought to the Tesla cockpit pods —
|
||
current and future titles alike. This is the integration
|
||
contract from the game's point of view: what your package must look like so the
|
||
operator console can **deploy** it to pods, and what your executable must speak
|
||
so the console can **command** it through a mission.
|
||
|
||
Everything here is implemented and validated in this repo (TeslaSuite v4.11.4.x)
|
||
— file references point at the authoritative source.
|
||
|
||
---
|
||
|
||
## 1. The big picture: two independent channels
|
||
|
||
A pod (cockpit PC) runs two things that matter to you:
|
||
|
||
| Channel | Port | Who listens | Purpose |
|
||
|---|---|---|---|
|
||
| **Launcher RPC** | TCP **53290** | `TeslaLauncher.exe` (pod tray app) | Deploy: install/uninstall packages, register launch entries, launch/kill your exe, volume, reboot |
|
||
| **Munga game control** | TCP **1501** | **your game exe** | Command: mission load (the "egg"), run/stop/abort/suspend/resume, state polling, in-mission events |
|
||
|
||
These are separate. The launcher channel is fully game-agnostic — any exe can be
|
||
deployed and launched with **zero code changes** to your game. The Munga channel
|
||
is what your game implements if the console is to drive missions in it.
|
||
|
||
That split gives two integration tiers:
|
||
|
||
- **Tier 0 — deploy + launch only.** The console installs your package, starts
|
||
and stops your exe, and keeps it alive (watchdog). Your game runs its own show.
|
||
Examples in the shipped catalog: BattleTech Firestorm, RIOJoy.
|
||
Requires only §2 (a package + a catalog entry).
|
||
- **Tier 1 — full mission command.** Your game is a Munga TCP server; the console
|
||
streams it a mission egg, drives the state machine, and receives scoring
|
||
events. Examples: Red Planet 4.11 (`rpl4opt.exe`), BattleTech 4.11
|
||
(`btl4.exe`), TeslaRel410 (supervisor wrapping the DOS games). Requires §2 + §3,
|
||
plus a console-side game module (§3.7).
|
||
|
||
There is one escape hatch: a game that Munga control would not serve well may
|
||
ship its own dedicated **game console** instead (§3.9) — deployment still goes
|
||
through Tier 0 unchanged.
|
||
|
||
---
|
||
|
||
## 2. Deployment spec (Tier 0 — every game needs this)
|
||
|
||
### 2.1 The package zip
|
||
|
||
The console's **Manage Site → Install Product** streams a zip to the pod; the
|
||
launcher extracts it into the games root **`C:\Games`** (the zip is opened at
|
||
that root, not inside a product folder). Lay the zip out as:
|
||
|
||
```
|
||
YourGame.zip
|
||
├── YourGame\ ← your product folder → becomes C:\Games\YourGame\
|
||
│ ├── yourgame.exe
|
||
│ ├── (data files...)
|
||
│ └── pre-uninstall.bat ← optional; run on uninstall (driver/config removal)
|
||
└── postinstall.bat ← optional; at ZIP ROOT; run once after extract, then deleted
|
||
```
|
||
|
||
Rules and lifecycle (implementation: [Launcher/TeslaLauncher.cs](Launcher/TeslaLauncher.cs),
|
||
[Launcher/MiniZip.cs](Launcher/MiniZip.cs)):
|
||
|
||
- **Everything must extract under one `C:\Games\<Product>\` folder** (plus the
|
||
optional root `postinstall.bat`). Uninstall deletes `C:\Games\<Product>`
|
||
recursively — don't scatter files elsewhere unless `postinstall.bat` puts them
|
||
there and `pre-uninstall.bat` removes them.
|
||
- **`postinstall.bat`** (zip root) runs after extraction with the launcher's
|
||
token — the kiosk account is an Administrator, so driver installs work (RIOJoy
|
||
installs ViGEmBus this way). It is waited on, then deleted.
|
||
- **`pre-uninstall.bat`** (inside your product folder) runs before the folder is
|
||
deleted on uninstall.
|
||
- Zip format: stored + deflate (+ ZIP64) — the launcher uses its own extractor
|
||
(`MiniZip.cs`), no exotic compression methods.
|
||
- Install progress reported to the operator: 0–50% receive, 50–95% extract,
|
||
~96% postinstall, 99–100% complete.
|
||
- **OS range:** pods run **Windows XP SP3 through Windows 11** on one image.
|
||
The *suite itself* is deliberately held to the XP floor (one net40 binary
|
||
set) to retain compatibility with the original cockpit hardware. For new
|
||
games, XP support is a **nice-to-have, not a requirement**: meeting it
|
||
(native exes: x86 + XP-safe API surface; .NET exes: net40 — runs in-place on
|
||
Win10/11's 4.8 runtime) lets your game reach the original-hardware pods too.
|
||
If you skip it, note modern-pods-only in your catalog entry's comment so
|
||
operators don't push it to XP-era machines.
|
||
|
||
Existing package builders to crib from: [vPOD/pack.ps1](vPOD/pack.ps1)
|
||
(minimal) and TeslaRel410's `deploy\package.ps1` (in its own repo — produces
|
||
an Install-Product-ready zip with postinstall).
|
||
|
||
### 2.2 The catalog entry (`Apps.xml`)
|
||
|
||
The console's product menu is data-driven from
|
||
[Console/RedPlanet/Apps.xml](Console/RedPlanet/Apps.xml) (parser:
|
||
[Console/TeslaConsole/AppRegistry.cs](Console/TeslaConsole/AppRegistry.cs)).
|
||
Your game ships as one `<Product>` element:
|
||
|
||
```xml
|
||
<Product id="NEW-GUID-HERE" ← fresh Guid; also the install key
|
||
name="Your Game" ← friendly name (menus, status text)
|
||
menuText="Your Game..." ← exact Install Product submenu text
|
||
hostTypeDialog="false"> ← "true" only if you have LC/MR roles
|
||
<Launch key="NEW-GUID-HERE" ← first entry reuses the product id
|
||
displayName="Your Game" ← name in the pod's app list
|
||
exe="C:\Games\YourGame\yourgame.exe"
|
||
args="-net 1501{res}" ← whatever your exe takes; see below
|
||
workingDirectory="" ← optional; defaults to exe's folder
|
||
autoRestart="true"
|
||
hostType="None" /> ← GameClient|LiveCamera|MissionReview|None
|
||
</Product>
|
||
```
|
||
|
||
- **Key convention** (documented in the Apps.xml header — follow it exactly):
|
||
generate ONE fresh Guid for the product id; the first `<Launch>` reuses it;
|
||
each additional `<Launch>` increments the **last hex digit** (+1, +2…,
|
||
wrapping F→0). Never append `-1`/`-2` to the string — keys parse as
|
||
`System.Guid` and a suffixed string silently collapses to `Guid.Empty`.
|
||
- **`{res}`** in `args` expands to ` -res W H` when the operator picks a custom
|
||
resolution, else to nothing. Only use it if your exe accepts `-res W H`
|
||
(the RP411 engine convention); a game with different resolution flags just
|
||
pins them in `args`.
|
||
- **`autoRestart="true"`** enables the pod watchdog (§2.3). Almost always what
|
||
you want for a game client.
|
||
- **`hostTypeDialog="true"` + per-entry `hostType`** is for games with separate
|
||
live-camera / mission-review roles (RP/BT use `-lc` / `-mr` flags) — see §4
|
||
for what those stations do. A plain game ships one entry with
|
||
`hostType="None"` and `hostTypeDialog="false"`.
|
||
- XML gotcha: comments in this file must not contain `--` — `XmlDocument.Load`
|
||
throws and the whole catalog comes up empty.
|
||
|
||
Registering entries on pods does **not** require reinstalling files: the
|
||
console's **Register Product on Pods** context action pushes the catalog's
|
||
launch entries to connected pods over the `InstallApp` RPC. The wire shape is
|
||
`LaunchData { LaunchPair{LaunchKey, DisplayName}, WorkingDirectory, ExeFile,
|
||
Arguments, AutoRestart }` ([Contract/WireContract.cs](Contract/WireContract.cs)).
|
||
|
||
### 2.3 Launch / kill / watchdog semantics
|
||
|
||
What the launcher does with your entry
|
||
([Launcher/TeslaLauncher.cs](Launcher/TeslaLauncher.cs)):
|
||
|
||
- **LaunchApp** starts `exe` with `args`, working directory = `workingDirectory`
|
||
or the exe's folder. Missing exe → clean "registered but not yet installed"
|
||
error at the console (register-first / install-later is supported).
|
||
- **Kill** terminates the process. Console-ordered kills stay down.
|
||
- **Watchdog:** an `autoRestart` entry whose process **exits on its own** is
|
||
relaunched ~2 s later. The original games lean on this for their per-mission
|
||
cycle: `rpl4opt`/`btl4` **terminate after each mission** and the watchdog
|
||
brings a fresh process up waiting for the next egg. That exit-and-relaunch
|
||
cycle is **not strictly required** (FireStorm doesn't do it): a game may
|
||
instead stay resident and return itself to a dark waiting state, ready for
|
||
the next group (§3.6). Either way, design your exe so a cold start goes
|
||
straight to that ready state with no menus in the way — the watchdog is
|
||
still your crash recovery.
|
||
- Your process runs in the auto-logged-in kiosk session (account `Firestorm`,
|
||
Administrator, UAC disabled) — desktop, audio, and DirectX/OpenAL are all
|
||
available. Firewall is disabled on pods; don't ship your own rules.
|
||
|
||
---
|
||
|
||
## 3. Command spec (Tier 1 — the Munga protocol)
|
||
|
||
Reference implementations, in order of usefulness:
|
||
|
||
- **[vPOD/MungaPodServer.cs](vPOD/MungaPodServer.cs)** — the framing, complete
|
||
and commented (vPOD is a working software pod; the console can't tell it from
|
||
a real one).
|
||
- **[vPOD/PodSimulator.cs](vPOD/PodSimulator.cs)** — the pod-side state machine
|
||
and egg handling.
|
||
- **[Console/TeslaConsole/MungaGame.cs](Console/TeslaConsole/MungaGame.cs)** —
|
||
the console side you're talking to.
|
||
- The typed message classes live in the vendored `Console/lib/Munga Net.dll`;
|
||
the C++ originals are in the RP411 game repo.
|
||
|
||
### 3.1 Transport
|
||
|
||
**Your game is the TCP server.** Listen on **TCP 1501**; the console connects to
|
||
`<podIP>:1501` and keeps one connection open. One console at a time (a new
|
||
connection replaces the old — see `MungaPodServer.AcceptLoop`). Convention: the
|
||
port is passed on your command line (`-net 1501`) rather than hardcoded.
|
||
|
||
### 3.2 Framing (little-endian throughout)
|
||
|
||
Every message, both directions:
|
||
|
||
```
|
||
[16-byte NetworkPacketHeader][MungaMessage]
|
||
header: int32 ClientID | int32 GameID | int32 FromHost | int32 Timestamp(ms tick)
|
||
message: int32 MessageLength | int32 MessageID | int32 Flags | body...
|
||
```
|
||
|
||
`MessageLength` counts the 12-byte message base **but not** the 16-byte header.
|
||
Messages are dispatched by **(ClientID, MessageID)** pairs.
|
||
|
||
### 3.3 Message set
|
||
|
||
Console → pod (what you must accept):
|
||
|
||
| ClientID | MessageID | Message | Your reaction |
|
||
|---|---|---|---|
|
||
| Application | 3 | `StateQuery` | reply `StateResponse(host, state, appId)` |
|
||
| Application | 4 | `CheckLoad` | (load probe) |
|
||
| Application | 5 | `RunMission` | `WaitingForLaunch → LaunchingMission → RunningMission` |
|
||
| Application | 6 | `StopMission` | `RunningMission → EndingMission → exit` (§3.6) |
|
||
| Application | 8 | `SuspendMission` | `RunningMission → SuspendingMission` (pause) |
|
||
| Application | 9 | `ResumeMission` | `SuspendingMission → ResumingMission → RunningMission` |
|
||
| Application | 10 | `LoadMission` | `WaitingForEgg → LoadingMission` |
|
||
| Application | 11 | `AbortMission` | `AbortingMission → WaitingForEgg` (no results) |
|
||
| Application | 12 | `LightsOutMission` | cockpit lights-out |
|
||
| NetworkManager | 3 | `EggFile` | egg chunk — buffer it (§3.5) |
|
||
|
||
Pod → console (what you send): `StateResponse` (answer to every `StateQuery`),
|
||
`AcknowledgeEggFile` (NetworkManager 4, once the egg is complete), and the
|
||
in-mission event messages (§3.6).
|
||
|
||
### 3.4 Identity and state
|
||
|
||
- **`ApplicationID`** — which game this pod is running, reported in every
|
||
`StateResponse`. The enum lives in `Munga Net.dll`: `RPL4 = 0` (Red Planet),
|
||
`BTL4 = 1` (BattleTech), plus `NDL4`. **A brand-new title needs a new value**
|
||
agreed with the TeslaSuite side (the console maps `ApplicationID` → game
|
||
module), or it reuses an existing one if it's a port of that game.
|
||
- **`ApplicationState`** — the cockpit state machine. The values the console
|
||
drives/observes: `InitializingState, WaitingForEgg, LoadingMission,
|
||
WaitingForLaunch, LaunchingMission, RunningMission, SuspendingMission,
|
||
ResumingMission, EndingMission, AbortingMission, CreatingMission`.
|
||
- The console polls `StateQuery` about **once per second** and gates every
|
||
operator action on your reported state. Report honestly — the console's UI
|
||
("busy, must stop first", ready-to-run, etc.) is driven entirely by it.
|
||
|
||
The normal lifecycle:
|
||
|
||
```
|
||
boot → InitializingState → WaitingForEgg
|
||
← egg streamed (console sends it when it sees WaitingForEgg)
|
||
→ LoadingMission → WaitingForLaunch (send AcknowledgeEggFile)
|
||
← RunMission
|
||
→ LaunchingMission → RunningMission
|
||
← StopMission (once, at mission end)
|
||
→ EndingMission → back to WaitingForEgg, either by:
|
||
exiting (watchdog relaunches a fresh process — the original games), or
|
||
resetting in-process to a dark waiting state
|
||
```
|
||
|
||
### 3.5 The egg (mission definition)
|
||
|
||
The console streams the mission as **`EggFileMessage` chunks of ≤1000 bytes**
|
||
(`index, totalLength, thisLength, buffer`). Reassemble by index until
|
||
`totalLength` bytes have arrived, then send **`AcknowledgeEggFileMessage`** and
|
||
move to `LoadingMission`.
|
||
|
||
Content: ASCII, INI-style sections, with every `key=value` separated by **NUL**
|
||
(`\0`) on the wire (the console builds it with `\n` separators and replaces them
|
||
before encoding). Parse by section name — section **order is not guaranteed**.
|
||
General shape (full field-by-field spec for an existing game:
|
||
[410console/battletech-port/BATTLETECH-PORT-SPEC.md](410console/battletech-port/BATTLETECH-PORT-SPEC.md) §2):
|
||
|
||
```
|
||
[mission] adventure= map= scenario= time= weather= temperature= length=...
|
||
[pilots] pilot=<podIP> ← one line per participant
|
||
[<podIP>] hostType= name= vehicle= dropzone= color= ... ← per-participant
|
||
[ordinals] 1st–4th place plasma bitmaps (128×32)
|
||
[BitMap::Large::<pilot>] 128×32 pilot-name plasma bitmap
|
||
[BitMap::Small::<pilot>] 64×16 variant
|
||
```
|
||
|
||
- Participants are keyed by **pod IP**. `hostType` assigns the pod's role:
|
||
`0` = game machine, `2` = mission review / camera, `3` = console
|
||
([Console/TeslaConsole/HostType.cs](Console/TeslaConsole/HostType.cs)).
|
||
- The `[BitMap::*]`/`[ordinals]` sections are pre-rendered graphics for the
|
||
cockpit's 128×32 plasma scoreboard — the console authors them; your game just
|
||
forwards them to the plasma display if the cockpit has one.
|
||
- Egg *content* is game-specific; the envelope above (chunking, ack, NUL
|
||
delimiting, sections) is fixed.
|
||
|
||
### 3.6 Mission end, events, results
|
||
|
||
- **In-mission events** are pod → console `MungaMessage`s. Red Planet sends
|
||
`Scored / Killed / Damaged / Boost / ScoreUpdate`; BattleTech's set maps its
|
||
DamageMatrix/KillMarker model. Your game defines its own set, but the console
|
||
module (§3.7) must know how to decode it — coordinate the two.
|
||
- **Mission end / egress:** the console is the **sole mission timekeeper**. It
|
||
sends **one** `StopMission` when mission time expires. Any end-of-mission
|
||
ritual (RP/BT hold pilots in the cockpit ~30 s of egress) is the *game's* own
|
||
behavior after receiving it — the console does not send a second stop. After
|
||
egress the game must end up back in a **dark waiting state** reporting
|
||
`WaitingForEgg`, ready for the next group. The original games get there by
|
||
**exiting** — the launcher watchdog relaunches a fresh process (§2.3) and the
|
||
console reconnects — but staying resident and resetting in-process is equally
|
||
valid (FireStorm-style); the console only acts on the state you report and
|
||
tolerates either a dropped-and-reconnected or a continuously open socket.
|
||
- `AbortMission` is the operator bailing out: return to `WaitingForEgg`
|
||
(via `AbortingMission`), no results expected.
|
||
|
||
### 3.7 The console side of Tier 1
|
||
|
||
Commanding a game isn't only pod-side work — the console needs a per-game module
|
||
that builds the egg and provides the mission UI:
|
||
`Console/TeslaConsole.<YourGame>/` mirroring
|
||
[Console/TeslaConsole.RedPlanet/](Console/TeslaConsole.RedPlanet/)
|
||
(mission classes + `ToEggString()`, a config XML catalog of maps/vehicles/
|
||
scenarios, the game pane driving `MungaGame`). The BattleTech port spec
|
||
([BATTLETECH-PORT-SPEC.md](410console/battletech-port/BATTLETECH-PORT-SPEC.md))
|
||
is the worked example of adding one — budget for it in your plan, and open the
|
||
conversation with the TeslaSuite maintainers early (ApplicationID assignment,
|
||
event vocabulary, egg fields).
|
||
|
||
### 3.8 If your game already has its own control protocol
|
||
|
||
Precedent: BattleTech FireStorm (MechWarrior 4) speaks **CTCL** on ports
|
||
1000/1001, not Munga — researched and parked in
|
||
[FIRESTORM-CTCL.md](FIRESTORM-CTCL.md). The standing guidance: **do not teach
|
||
the console a second protocol**. Put an adapter on the pod that speaks Munga to
|
||
the console and your native protocol to the game (TeslaRel410 does exactly this:
|
||
`pod-launch.exe` supervises the DOS game and fronts for it). The console then
|
||
sees a normal Munga pod.
|
||
|
||
### 3.9 Escape hatch: a dedicated game console
|
||
|
||
If Munga control — direct or through a §3.8 adapter — would be **limiting or
|
||
detrimental to the game experience** (the mission model doesn't map to the
|
||
egg/state machine, the game needs richer or real-time operator control than
|
||
load/run/stop, the adapter would cost fidelity), you may instead build a
|
||
separate **game console**: a purpose-built operator application for your game,
|
||
run on the console computer alongside TeslaConsole. FireStorm is the precedent —
|
||
MechWarrior 4 venues ran their own dedicated console rather than bending the
|
||
game to the Tesla mission model ([FIRESTORM-CTCL.md](FIRESTORM-CTCL.md)).
|
||
|
||
Rules if you take this path:
|
||
|
||
- **It ships inside the same deployment zip as the pod-side game.** One Install
|
||
Product archive is the whole product — no separate installer, no side-channel
|
||
distribution. Put it in a subfolder of your product
|
||
(e.g. `YourGame\GameConsole\`); the pod-side extraction just carries the
|
||
folder along, and the operator runs it from that same archive on the console
|
||
machine.
|
||
- It runs on the **console computer**, never on pods.
|
||
- **TeslaConsole still owns deployment and process lifecycle** (§2):
|
||
install/uninstall, launch/kill, and the watchdog all stay on the launcher
|
||
channel. Your game console owns only in-game command — it is a replacement
|
||
for §3.1–3.7, not for §2.
|
||
- Don't collide with the suite's ports on either end: 1501, 53290, 53291/53292
|
||
are spoken for.
|
||
|
||
---
|
||
|
||
## 4. Presentation: live camera, mission review, score sheets
|
||
|
||
A pod bay is more than cockpits: spectators watch the current game on a bay
|
||
display, players coming out of the pods watch a replay at the mission-review
|
||
station, and everyone walks away with a printed score sheet. Plan for all
|
||
three.
|
||
|
||
### 4.1 The bay address plan
|
||
|
||
Modern bay deployments follow the FireStorm/CTCL site layout: squads of eight
|
||
pods per address decade, with the `9`/`10` slots of each decade reserved for
|
||
stations.
|
||
|
||
| Address | Station |
|
||
|---|---|
|
||
| `x.x.x.1–8` | Pods, squad 1 |
|
||
| `x.x.x.9` | **Live camera** |
|
||
| `x.x.x.10` | **Operator console** |
|
||
| `x.x.x.11–18` | Pods, squad 2 |
|
||
| `x.x.x.19` | **Mission review** |
|
||
| `x.x.x.20` | **Score-sheet printer** |
|
||
| `x.x.x.21–28` | Pods, squad 3 |
|
||
| `x.x.x.31–38` | Pods, squad 4 — and so on: pods at `1–8` of every further decade, `9`/`10` slots reserved for future stations |
|
||
|
||
(Legacy RP/BT-era installs used the `200.0.0.x` scheme with the console at
|
||
`.1` and pods from `.11`. The suite doesn't hardcode either — addressing is
|
||
per-site via Manage Site — but new bays should follow the plan above.)
|
||
|
||
### 4.2 Live camera — presenting the current game
|
||
|
||
The live-cam station runs your game exe in a **spectator role**, rendering the
|
||
running mission on the bay display. The RP/BT model, which the console
|
||
generalizes:
|
||
|
||
- The station is a pod like any other — installed, launched, watchdogged —
|
||
whose catalog launch entry has `hostType="LiveCamera"`; RP/BT pass a `-lc`
|
||
flag so the exe boots into the camera role (§2.2).
|
||
- The console enrolls every enabled camera station in the mission as a
|
||
**camera participant**: it receives the same egg and walks the same Munga
|
||
state machine as a game pod, but its participant block says `hostType=2`,
|
||
`vehicle=camera`, `name=Camera`, `loadzones=0`
|
||
([RPCamera.cs](Console/TeslaConsole.RedPlanet/RPCamera.cs)).
|
||
- Your game's job in the role: observe the running mission and render a
|
||
spectator view — no cockpit input, no scoring participation. The camera's
|
||
view of the action travels over the game's own network traffic between pods;
|
||
the console only issues the egg and state commands.
|
||
|
||
### 4.3 Mission review — replaying the finished game
|
||
|
||
The mission-review station **replays the completed mission** for the players
|
||
who just climbed out. To the console it looks exactly like the live cam — a
|
||
`hostType="MissionReview"` catalog entry (`-mr` flag in RP/BT), enrolled as an
|
||
egg camera participant — the difference is entirely inside your game: the MR
|
||
role captures the mission as it runs and replays it on demand afterwards.
|
||
|
||
**Replay capture and playback are the game's responsibility.** The console does
|
||
not record or transport replay data: RP/BT capture from the game's own network
|
||
traffic; FireStorm writes `{guid}.mr` files pod-side and its console points the
|
||
review station at them ([FIRESTORM-CTCL.md](FIRESTORM-CTCL.md)).
|
||
|
||
### 4.4 Score sheets
|
||
|
||
Players get a printed score sheet. How it works for a Tier 1 game:
|
||
|
||
- During the mission the console builds results from your **in-mission event
|
||
messages** (§3.6) via the game module's mission recorder
|
||
([RPMissionRecorder.cs](Console/TeslaConsole.RedPlanet/RPMissionRecorder.cs)).
|
||
The event vocabulary is what makes score sheets possible — a game that
|
||
reports no events has nothing to print.
|
||
- The game module renders the results as a print document
|
||
([RPPrintDocument.cs](Console/TeslaConsole.RedPlanet/RPPrintDocument.cs)).
|
||
The operator's **Auto Print** checkbox prints each mission as it ends;
|
||
**Print Last Mission** reprints on demand. Output goes to the bay's
|
||
score-sheet printer (`x.x.x.20`, a network printer configured on the console
|
||
machine).
|
||
- A §3.9 dedicated game console owns its own scoring and printing (FireStorm:
|
||
the game writes `{guid}.pr` files pod-side, the console hands them to the
|
||
`mw4print` helper) — it should print to the same bay printer.
|
||
|
||
---
|
||
|
||
## 5. Pod environment reference
|
||
|
||
| Fact | Value |
|
||
|---|---|
|
||
| OS range | Windows XP SP3 → Windows 11, one binary set (.NET products: net40) |
|
||
| Session | auto-login kiosk account `Firestorm` (Administrator, UAC off) |
|
||
| Games root | `C:\Games\<Product>\` |
|
||
| Launcher state | `<CommonAppData>\TeslaLauncher\` (`LaunchApps.xml`, key store, log) |
|
||
| Network plan | squads of 8 pods per address decade; live cam `.9`, console `.10`, mission review `.19`, printer `.20` — see §4.1 |
|
||
| Ports | 1501 TCP game control (your game listens) · 53290 TCP launcher RPC · 53291/53292 UDP first-boot provisioning |
|
||
| Cockpit extras | 128×32 plasma scoreboard on COM2; RIO board cockpit controls — native integration preferred, RIOJoy shim optional (§5.1) |
|
||
| Firewall | disabled by the pod installer |
|
||
|
||
### 5.1 Cockpit controls: the RIO board
|
||
|
||
The cockpit's controls come in through the **RIO board**. Two integration
|
||
paths:
|
||
|
||
- **Native RIO integration — preferred.** Talk to the board directly, as the
|
||
original games do (FireStorm's `CRIOMAIN.CPP` is the documented precedent).
|
||
This is the only path that reaches the board's **output side** — the
|
||
**cockpit lighting** — which native games get as a feedback channel to the
|
||
player. A game that only reads a gamepad can't touch it.
|
||
- **RIOJoy — optional shim.** A deployable catalog product that feeds RIO
|
||
board input into a virtual gamepad (RioGamepad HID via the ViGEmBus driver;
|
||
Win10+ only) with per-game mapping profiles. Zero game-side changes — if
|
||
your engine already reads a standard gamepad, a RIOJoy profile gets a
|
||
cockpit playable. **Input only:** no lighting, no feedback.
|
||
|
||
A RIOJoy profile is a fine way to get playable quickly during development;
|
||
plan on native RIO integration for the real deployment so the cockpit lighting
|
||
works for your game. (The board interface and the feeder implementation live
|
||
in the RIOJoy repo.)
|
||
|
||
---
|
||
|
||
## 6. Testing your integration without a pod bay
|
||
|
||
- **[vPOD/](vPOD/)** is a full software pod: it emulates the launcher side
|
||
(install your zip into a real `C:\Games`, launch/kill with the real watchdog
|
||
semantics) *and* the Munga side. Two ways to use it:
|
||
1. **Test your package/catalog entry:** run vPOD on any machine, provision it
|
||
from the console (README walk-through), Install Product your zip, launch —
|
||
with "Actually launch apps" checked your real exe runs.
|
||
2. **Test your Munga implementation:** point the console at your game instead
|
||
of vPOD (the shipped site has a `local` pod at `127.0.0.1` — run your exe
|
||
with `-net 1501` on the console machine). vPOD's egg viewer is also handy:
|
||
drive a mission at vPOD, copy the egg it captures, and use it as a fixture
|
||
for your parser.
|
||
- Console-side changes are pinned by the differential suite
|
||
([Console/tests/TeslaConsole.DiffTests](Console/tests/TeslaConsole.DiffTests)).
|
||
|
||
---
|
||
|
||
## 7. Checklists
|
||
|
||
**To make your game deployable (Tier 0):**
|
||
|
||
- [ ] Package zip: `<Product>\` folder + optional root `postinstall.bat`,
|
||
optional `<Product>\pre-uninstall.bat` (§2.1)
|
||
- [ ] Runs on your target pod OS range — XP SP3 support is a nice-to-have that
|
||
reaches the original hardware (x86 + net40 if .NET); if skipped, catalog
|
||
comment says modern-pods-only
|
||
- [ ] `Apps.xml` `<Product>` entry, key convention respected (§2.2)
|
||
- [ ] Cold start reaches gameplay/ready state unattended (kiosk + watchdog)
|
||
- [ ] Cockpit controls wired: native RIO integration preferred (enables
|
||
lighting feedback), RIOJoy profile acceptable (§5.1)
|
||
- [ ] Install → launch → kill → uninstall verified against vPOD
|
||
|
||
**To make your game commandable (Tier 1), additionally** *(or, if Munga control
|
||
would hurt the game: a dedicated game console per §3.9, shipped in the same
|
||
deployment zip)*:
|
||
|
||
- [ ] TCP server on 1501 (`-net` arg), Munga framing per §3.2
|
||
- [ ] `StateQuery` → `StateResponse` with an agreed `ApplicationID`
|
||
- [ ] Egg reassembly + `AcknowledgeEggFile` + state walk to `RunningMission`
|
||
- [ ] `Stop/Abort/Suspend/Resume` honored; after mission end, back to a dark
|
||
`WaitingForEgg` — by exiting (watchdog relaunch) or by in-process reset
|
||
- [ ] Event vocabulary agreed with the console module — rich enough for score
|
||
sheets (§4.4)
|
||
- [ ] Live-camera and mission-review roles: spectator rendering + replay
|
||
capture/playback in the game (§4.2–4.3), LC/MR catalog entries (§2.2)
|
||
- [ ] Console game module exists or is planned (§3.7)
|