Researched from the readable RP MUNGA source (BT shares the engine): host roles are assigned per-IP in the mission egg (hostType= on each pilot page); a CameraShip/MissionReview host gets a CameraDirector player that auto-cuts to the top-ranked pilot every 10s, with manual flight via the same cockpit hardware as pods (CameraRIOMapper) and fixed clamped trackside cameras authored in-game into MAPS/<map>.cam. Mission Review records raw NetworkPackets (SpoolFile -> last.spl) and replays them through a networkless playback app with timestamp bias -- the replay re-simulates the battle from replication traffic. Same BTL4OPT.EXE serves every role; standing up Live Cam on the emulated pod LAN is an egg edit, not a build. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
10 KiB
Live Cam & Mission Review — how the VWE games did it
Research notes, 2026-07-08. Sources: CODE/RP/MUNGA + CODE/RP/MUNGA_L4
(the readable Red Planet tree; BattleTech shares the MUNGA engine and has the
matching CODE/BT/BT_L4/BTL4PB.HPP + CODE/BT/MUNGA/SPOOLER.HPP), the
sda4/BTLIVE/MAPS/*.CAM files, and the mission eggs. Everything below is from
the code itself, not conjecture, except where marked.
Both features ride the same insight: the game is a replicated-entity
network simulation. Every machine on the mission LAN runs the full sim and
mirrors the others' entities from network traffic (master/replicant, see
HOST.HPP). A spectator view is therefore just one more host that renders
without piloting — and a replay is just the same network traffic played back
from a file.
1. Host roles come from the mission egg
HOST.HPP:41:
enum HostType {
GameMachineHostType, // 0 — a pod
CameraShipHostType, // 1 — Live Cam station
MissionReviewHostType, // 2 — replay station
ConsoleHostType // 3 — the ops console
};
The console assigns a role to every IP on the mission when it authors the
egg. Each [pilots] pilot=<ip> page carries a mandatory hostType= key
(MISSION.CPP:480 — boot aborts with "ERROR: no host type in egg!" if
absent). Our own cavern.egg shows a pod: [200.0.0.113] hostType=0 ....
At player-creation time, Registry::MakePlayer (REGISTRY.CPP:255) switches
on the local host's type:
GameMachineHostType→ an ordinaryPlayer(pod pilot);CameraShipHostType/MissionReviewHostType→ aCameraDirectorplayer (the comment notes "Not a CameraShip to run on a POD!").- Additionally, if the mission's
gamemodelfield is"camera", the player's vehicle getsCameraShipPlayerFlag— so a GameMachine host can also fly a camera ("VTV, Mech, CameraShip w/controls" per the comment).
The same game EXE serves every role — pod, camera, review — chosen purely by the egg. This is the actionable heart of it for us (§5).
2. Live Cam = CameraShip + CameraDirector
Classes: CAMSHIP.HPP/CPP (the flying camera vehicle, a Mover entity) and
DIRECTOR.HPP/CPP (the auto-director, a Player subclass).
- CameraDirector (
DIRECTOR.CPP:184 BeADirector): every frame it checkstimeLeftOnPlayer; when it expires it finds the top-ranked player (FindPlayerByRank(0)over the "Players" entity group) and, if the leader changed, dispatches aCameraShip::DirectionMessage{goalEntity, timeOnCamera, focusOffset}and resets the shot clock to 10 seconds. So the default broadcast is "follow the leader, re-cut every 10 s". - HUD (
DIRECTOR.CPP:118 UpdateHUD+CameraShipHUDRenderableinL4VIDRND.CPP:2199): the feed overlays the followed player's identity and a ranking window cycling 10 s on / 15 s off — always on during the final 30 s of the mission, hidden once the mission stops. - CameraShip (
CAMSHIP.CPP:340 FollowGoal): aims atfocusOffset × goal->localToWorld, tracks the goal's linear position, and asks the director for a new goal whentimeOnCameraruns out. Camera height is operator-adjustable (ApplyControlledCameraHeight).
Manual camera operation
CAMMPPR.HPP (CameraControlsMapper subsystem) + L4MPPR.HPP: the camera
station reads the same cockpit hardware as a pod — there are three
concrete mappers: CameraL4Mapper, CameraThrustmasterMapper, and
CameraRIOMapper (a full RIO cockpit could fly the camera). Attributes:
stick / throttle / pedals / reverse-thrust / drive-camera / slide-or-clamp.
Buttons: DirectorMode toggle (auto-director vs manual),
Increment/DecrementCamera (cut between fixed cameras), and
Create/Delete/OutputCameraInstances — the camera-authoring workflow.
Fixed trackside cameras — the .CAM files
CAMINST.HPP/CPP + CAMMGR.CPP (CameraInstanceManager): each map has a
notation file MAPS/<map>.cam (e.g. sda4/BTLIVE/MAPS/ARENA1.CAM)
holding [cameraN] pages:
[camera0]
cameraID=0
cameraType=DefaultCameraType ; or AlwaysSeesCameraType
tranx/y/z = position
quatx/y/z/w = orientation
minYawClamp/maxYawClamp ; pan limits (radians)
minPitchClamp/maxPitchClamp ; tilt limits
These are broadcast-style fixed cameras with pan/tilt clamps;
CameraInstance::CalculateCameraRotation pans them to track the goal within
the clamps. They were authored in-game: the operator flies to a spot,
presses CreateCameraInstance, and OutputCameraInstances writes the .cam
file back out (CameraInstanceManager::WriteNotationFile).
3. Mission Review = record the network, replay the network
Recording (SPOOLER.HPP/CPP, L4SPLR.HPP)
SpoolFileis aMemoryStreamof rawNetworkPackets (header + payload, back to back). States: Empty → Spooling → Stored → Playing.SpoolPacket()appends (hard-exits if the RAM buffer fills);SaveAs/Readmove it to/from disk. The canonical file name islast.spl(SPOOLER.CPP:251,274) — same "last mission" convention asLAST.EGG.MissionReviewApplicationManagerowns a pool ofspool_countRAM buffers ofspool_sizeeach.L4SpoolingApplication(+L4SpoolingNetworkManager,SpoolingInterestManager) is the recorder: itsReceiveNetworkPacket()override tees every packet arriving over the mission LAN into the active spool while also processing it normally — so the recording host fully participates (renders, directs cameras) as it records. AmissionSpooledflag tracks state; the spool is stored (→last.spl) when the mission stops.
Because the recorder simply captures received replication traffic, the recording is exactly what any spectator host saw: entity creations, state updates, weapon events, kills — everything needed to re-simulate the battle, at a tiny fraction of the size of video.
Playback (BTL4PB.HPP, L4SPLR.HPP)
BTL4PlaybackApplication(BT flavor ofRPPlaybackApplication) is a full game application whose network manager isL4PlaybackNetworkManager— aNetworkManagerwith no real network:CheckBuffers()sources packets from theSpoolFileinstead of the wire.SpoolerTask(anApplicationTask) walks the spool withNextPacket()andDispatchPacket()s each one into the app, usingtimeBiasto shift the recorded timestamps onto the playback clock — packets are released on the same relative schedule they were recorded, so the replayed entities move exactly as they did live.- The playback host's player is again a
CameraDirector(host type switch, §1) — so a review session is the Live Cam presentation (auto-cuts to the leader, ranking overlays, fixed trackside cameras) running over recorded traffic. This is what the debrief room / take-home tapes showed.
What's NOT in the repo
The readable tree is partial: L4SPLR.CPP (SpoolerTask::Execute pacing,
exact spool start/stop triggers) and BTL4PB.CPP are missing — only their
headers survive. The compiled implementations are in the era binaries. The
trigger for "start spooling" (console message vs automatic at mission start)
is therefore unconfirmed; the message-handler names
(Run/Stop/AbortMissionMessageHandler on the spooling app) suggest it simply
records from RunMission to StopMission.
4. The physical setup at a center (period context, inferred)
A "camera ship" machine = one more networked PC with a Division board, its
out-the-window video feeding the spectator monitors (and the VHS deck for
take-home tapes). The mission-review station = the same machine (or another)
replaying last.spl into the debrief room after the mission. Both could be
driven hands-off (CameraDirector) or by an operator with a joystick/RIO.
5. What this means for OUR pod project
- No new binary needed. BTL4OPT.EXE already contains all of it. A Live
Cam station = a second emulated machine on the pod LAN whose egg page
says
hostType=1. Mission Review =hostType=2+ alast.spl. - The console app owns the roles. When the TeslaSuite console port authors eggs, adding a camera-host page is how you light this up — it's an egg field, not a build variant.
- We can record spools ourselves. The spool format is trivial (length-
prefixed file of raw NetworkPackets,
SPOOLER.CPP:50-95); our emulated NIC path (slirp/pcap) could tee mission traffic into alast.splindependently of any spooling host — giving Mission Review of any pod session after the fact. - Camera authoring works from a cockpit.
CameraRIOMappermeans the vRIO can fly the camera ship and author.camfiles for our arenas. - Renderer note: a camera/review host renders through the same Division
wire our bridge already decodes — the bridge should work unchanged for a
spectator host, modulo the
CameraShipHUDRenderableoverlays (2D HUD layer, same 0x29/0x2b dpl2d path as the pod HUD).
Quick reference — the cast
| Piece | File | Role |
|---|---|---|
HostType enum |
MUNGA/HOST.HPP |
pod / camera / review / console, set per-IP in the egg (hostType=) |
Registry::MakePlayer |
MUNGA/REGISTRY.CPP |
host type → Player or CameraDirector |
CameraDirector |
MUNGA/DIRECTOR.* |
auto-director: cut to rank-0 player every 10 s; ranking-window HUD |
CameraShip |
MUNGA/CAMSHIP.* |
the flying camera vehicle (a Mover entity) |
CameraControlsMapper |
MUNGA/CAMMPPR.* |
stick/throttle/pedals camera flight, director toggle, camera authoring buttons |
CameraL4/Thrustmaster/RIOMapper |
MUNGA_L4/L4MPPR.* |
camera station input bindings (RIO cockpit supported) |
CameraInstance(Manager) |
MUNGA/CAMINST.*, CAMMGR.CPP |
fixed clamped cameras; reads/writes MAPS/<map>.cam |
SpoolFile |
MUNGA/SPOOLER.* |
NetworkPacket recording; last.spl on disk |
L4SpoolingApplication |
MUNGA_L4/L4SPLR.HPP |
records the mission LAN while participating |
BTL4PlaybackApplication + SpoolerTask |
BT_L4/BTL4PB.HPP |
replays the spool with timeBias re-timing; no real network |