vPOD now also impersonates the pod's TeslaLauncher service, so the console's Manage Site works against it unmodified: - LauncherRpcServer: ILauncherService over OFB + framed JSON on TCP 53290, mirroring TeslaLauncherService (concurrent sessions, out-of-band install zip on a second connection, the 99%-not-100 completion convention). Packages extract to %LocalAppData%\vPOD\Games; postinstall.bat is logged but never executed. - PodProvisioning: pod side of SecureConfig (RQST beacon, RPLY decrypt, RSA session-key exchange), display-only — never touches the NIC/registry. The console's Configure flow mints the key exactly as for a real pod; console Reconfigure (ClearStore) drops the key and re-enters beacon mode. - VirtualLauncher: installed-app registry (persisted), simulated launch PIDs, volume, install progress; console Shutdown/Restart power-cycles the pod. - Form gets a Launcher/Site Management column (passcode display, RPC status, install progress, app list, Reprovision); Power Off darkens the launcher side too; new -nomanage flag disables it. vPOD references the shared Tesla.Contract/Tesla.SecureConfig projects (server side of the existing contract only, no new RPCs). Loopback tests drive the real PodManagerConnection and PodConfigurationServer against the new code (VPodLauncherServerTests, VPodProvisioningTests) — suite now 99 green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vPOD — virtual pod / game-client stand-in
A test tool that impersonates a Tesla game client (Red Planet's rpl4opt.exe
or BattleTech's btl4.exe) so the operator consoles can be exercised without
real cockpit hardware. It speaks the Munga command/control protocol as a
server on TCP 1501 — the console connects to it exactly as it would a real pod —
emulates the pod ApplicationState machine, reassembles the streamed egg, and
shows everything on a live display.
It also impersonates the pod's TeslaLauncher service (the "Launcher / Site Management" column), so the console's Manage Site — provisioning, Install / Uninstall Product, launch/kill, volume, restart/shutdown — can be tested end-to-end with no cockpit and no console changes. See Site management / virtual launcher.
What it does
- Listens on TCP 1501 (configurable) and answers the console's
StateQuerywith aStateResponse, reporting the game (ApplicationID) and the currentApplicationState. - Walks the mission lifecycle the console drives it through:
WaitingForEgg → LoadingMission → WaitingForLaunch → LaunchingMission → RunningMission → …, reacting to the egg stream and to Run / Stop / Abort / Suspend / Resume messages, and acknowledging the egg. - End-mission graceful exit + watchdog restart — on the console's end-mission
command the "game exe" exits (the listener closes, the console's connection
drops), then a watchdog relaunches it a moment later and it comes back up in
WaitingForEgg. This is the real pod's per-game cycle (autoRestart); the Restart game after mission ends (watchdog) checkbox (on by default) toggles it — unchecked, the pod just returns toWaitingForEggwithout exiting. - Power On / Power Off — Power Off closes the TCP listener so the console
cannot connect, mimicking a pod with no game client running; Power On reopens
it. Reset returns a live pod to
WaitingForEgg. - Reassembles and shows the egg the console streams (the
EggFileMessagechunks), one field per line, with a summary line (adventure / map / scenario / pilot count). The last egg is kept across missions/restarts (so it can be copied for dev use) until the Clear button empties the viewer. - Game toggle — a Red Planet ⇄ BattleTech switch on the window changes which
ApplicationIDthe pod reports, live, so one vPOD can stand in for either game. (-app rp|btsets the initial choice.) - A newest-first protocol log of the traffic.
Running it
vPOD.exe [-net <port>] [-app rp|bt] [-lc|-mr] [-host <id>] [-res W H] [-nomanage]
-net <port>Munga control port (default 1501).-app rp|btwhich game to report initially (also switchable in the UI).-lc/-mrlive-camera / mission-review role (cosmetic; the state model is identical to a game machine).-host <id>responding host id reported in state responses (default 1).-res W Haccepted and ignored (real clients take it; kept for drop-in launch compatibility).-nomanagevPOD-only: disable the virtual launcher / site-management side (no provisioning beacons, no TCP 53290 listener) — e.g. when a real TeslaLauncher runs on the same machine, or for a second vPOD instance.
Site management / virtual launcher
vPOD's right-hand column is a stand-in for the pod's TeslaLauncher service:
the OFB-encrypted, framed-JSON ILauncherService RPC on TCP 53290 that the
console's Manage Site and squad/pod panel talk to (Tesla.Contract /
Tesla.SecureConfig are the same shared wire libraries both real ends use).
Provisioning (first run)
The console only talks to a pod's launcher after minting a 32-byte session key for it via the SecureConfig Configure flow, so an unprovisioned vPOD behaves like a freshly-imaged pod — minus the NIC/registry changes (the assigned network config is shown in the window but never applied):
- Run vPOD (no
-nomanage). It broadcastsRQSTbeacons and displays a Request ID and Passphrase (the real pod shows these on its screen). - In the console: Manage Site — a "Configure <Request ID>" button appears at the bottom. Click it, enter the pod's name/squad, its IP (127.0.0.1 when vPOD runs on the console machine — accepted), any subnet (e.g. 255.255.255.0), and the passphrase from vPOD's window.
- The console sends the encrypted config + session key; vPOD stores the key
and starts the launcher RPC. The pod row goes healthy (
Idle [<n> ms]).
The key persists in %LocalAppData%\vPOD\TeslaKeyStore.key (launcher format),
so provisioning is one-time. Reprovision drops the key and returns to
beacon mode — pair it with deleting the pod in Manage Site (the console's
Reconfigure… does both ends automatically: its ClearStore makes vPOD
drop the key and beacon again).
Product deployments
Right-click the pod row → Install Product ▸ works exactly as against a real
pod: the console streams the package zip out-of-band on a second 53290
connection while polling progress on the first; vPOD extracts it into its
virtual games root and reports the launcher's usual 0–50% receive / 50–95%
extract / 99% Complete progression. Then:
- Installed apps land in the column's list (and in
GetInstalledApps, so the Uninstall menu populates). Registrations persist in%LocalAppData%\vPOD\LaunchApps.json. - Packages extract under
%LocalAppData%\vPOD\Games\(the virtualC:\Games). A packagedpostinstall.batis logged and removed but never executed. - Launch/Kill from the squad panel are simulated (fake PIDs, no real process); Volume round-trips; Restart/Shutdown power-cycle the virtual pod (dark for a few seconds on restart).
Ports
| Port | Proto | Direction | Purpose |
|---|---|---|---|
| 1501 | TCP | console → vPOD | Munga game control (existing) |
| 53290 | TCP | console → vPOD | Launcher RPC (ILauncherService) |
| 53291 | UDP | vPOD → console (broadcast) | RQST provisioning beacon |
| 53292 | UDP+TCP | console → vPOD | RPLY config broadcast + RSA key exchange |
Same-machine testing needs no firewall changes (loopback). Running vPOD on a different machine needs inbound allows for TCP 1501/53290/53292 and UDP 53292 on the vPOD machine (the console installer already opens its own side).
Not emulated: the console's remote Windows-service control (ServiceController
over SCM/SMB, used by some SitePanel service start/stop paths — dormant against
real pods too, since it queries service name TeslaLauncherService while the
launcher registers as Tesla Application Launcher), and really launching
deployed exes (a second game client would fight vPOD for its own ports).
An end-to-end loopback test of this server against the console's real
PodManagerConnection client lives in the differential suite:
Console/tests/TeslaConsole.DiffTests/VPodLauncherServerTests.cs.
Deploying from the console (Manage Site → Install Product)
vPOD is a catalog product (RedPlanet\Apps.xml, id 0041C870-…) with Game
Client / Live Camera / Mission Review entries, so it appears in Manage Site →
Install Product like any game. Build the deployable package first:
pwsh -File pack.ps1 # produces dist\vPOD.zip
The zip lays out vPOD\vPOD.exe (+ Munga Net.dll) so the launcher extracts it
to C:\Games\vPOD and the catalog entry launches C:\Games\vPOD\vPOD.exe.
Testing locally against the console
The default site ships a local pod at 127.0.0.1. Run vPOD on the console
machine, open a game window (e.g. Games → Red Planet: Death Race), and enable
the local pod — the console connects to 127.0.0.1:1501 (vPOD), and you can
drive Load → Run → Stop and watch vPOD's state and egg viewer follow along.