--- id: glass-cockpit title: "Glass Cockpit — the desktop developer layer (BT_GLASS / BT_STEAM)" status: living source_sections: "plan 2026-07-17; CMakeLists.txt gates; BT412 prior art (reference only)" related_topics: [pod-hardware, build-and-run, multiplayer, gauges-hud] key_terms: [PadRIO, miniconsole, glass-cockpit] open_questions: [] --- # Glass Cockpit — the desktop developer layer **Purpose:** developer tooling so game developers can test their work WITHOUT booting a Tesla II pod — and stay far enough out of the game that nothing a real pod requires can break. NOT a consumer product (GDI-grade UI is the ceiling). Pod fidelity outranks desktop convenience in every trade-off. ## The compile gates (the ONLY compile-time feature gates in the tree) | Gate | Default | Adds | |---|---|---| | `BT_GLASS` | OFF | PadRIO input (XInput+keyboard), on-screen cockpit button panel, desktop plasma window, `glass` platform preset, miniconsole mission launcher | | `BT_STEAM` | OFF (requires `BT_GLASS`) | Steam transport (`ISteamNetworkingSockets`) + `ISteamMatchmaking` lobby | - A **no-flags configure is the pure pod game** — the build of record. `cmake` options are cached, so a developer configures a `build/` with `-DBT_GLASS=ON` once. - Build dirs: `build-pod/` (defaults, purity), `build/` (dev, glass ON), `build-steam/` (ON/ON). - **Convention:** `BT_GLASS`/`BT_STEAM` are compile gates; every other `BT_*` name is a RUNTIME env gate (`BTEnvOn`) — do not add compile gates without updating this file. - No weak-linkage/optional symbols — `/FORCE` turns unresolved externals into runtime AVs ([[reconstruction-gotchas]]); gated calls must be structurally present-or-absent at compile time. ## Plan of record (2026-07-17) Working branch `glass-cockpit` (from master `e2c21c4`). Steps: (1) gates+scaffolding [THIS], (2) PadRIO glass cockpit, (3) miniconsole self-launch, (4) Steam transport+lobby. Full plan: the approved plan file; running detail: `docs/GLASS_COCKPIT.md`. The retired BT412 trees (`C:\VWE\BT412`; local branch `local-abandoned-20260717`) are read-only reference — no code is copied from them. ## Status - **Step 1 (gates + scaffolding): DONE 2026-07-17.** CMake options + defines; 3-config configure matrix + negative test + defaults build verified. - **Step 2a (.CTL id audit): DONE 2026-07-17 [T2].** The streamed `.CTL` positional ids landed every `MechControlsMapper` record ONE MEMBER LATE (our chain starts at 2, the binary's at 3) — a latent REAL-POD bug (RIO throttle would drive pedalsPosition), masked on dev boxes by the keyboard bridge. Fixed ungated: ids pinned to binary numbering + id-2 pad + static_assert locks (`mechmppr.hpp/.cpp`); torso/weapon chains were already aligned. Permanent env-gated diagnostic: `BT_CTRLMAP_LOG=1` dumps every streamed record's resolved member offset (`L4CTRL.cpp CreateStreamedMappings`). Full evidence: `docs/GLASS_COCKPIT.md` §2a. - **Step 2 (PadRIO glass cockpit): DONE 2026-07-17 [T2].** `RIOBase` seam (`L4RIO.h`, unconditional) + gated `L4CONTROLS=PAD` → `PadRIO` (`L4PADRIO.*` XInput+keyboard, `L4PADBINDINGS.*` `content\bindings.txt`); bridge stand-downs auto-yield to a live device (`BTRIODevicePresent`, `BT_KEY_BRIDGE` unset=auto/0=off/1=on); on-screen panel `L4PADPANEL.*` follows **vRIO** (`C:\VWE\vrio` CockpitLayout/PanelCanvas — 104 controls incl. the two hex keypads → real KeyEvents; right-click latch); desktop plasma `L4PLASMAWIN.*` (`L4PLASMA=SCREEN`, buffer is top-down); `-platform glass` preset + run.cmd token. Secondary displays reuse the EXISTING dev-gauge modes (dock / `BT_DEV_GAUGES_WINDOW=1` window / `_DOCK=1` overlay — [[gauges-hud]]); no new MFD code, no `L4VB16.cpp` exposure. **Button-trap guard:** base `ConfigureMappableMessageHandler` no longer `abort()`s by default (`BT_BUTTON_TRAP=1` restores) — each `[FAIL]` log = a missing L4 override to reconstruct. Verified: authentic-path input (engine push → streamed `.CTL` → mapper), panel-click survival, 2-node loopback MP un-regressed on the pod build. Detail: `docs/GLASS_COCKPIT.md`. - **Step 3 (miniconsole): DONE 2026-07-17 [T2].** `game/glass/btl4fe.*` (menu + console-shape egg writer, golden-tested vs MP.EGG) + `btl4console.*` (the marshal: a worker-thread console CLIENT speaking the btconsole.py wire verbatim; `content\marshal.log`). ZERO engine hooks — the engine runs the stock console ladder. Per-mission process relaunch; `BT_FE_*` env arms the marshal (menu relaunches clear it). Verified: solo cycle (menu→mission→60s clock→stop→menu) and menu-hosted 2-node LAN. - **Step 4 (Steam): CODE COMPLETE 2026-07-18 [T2 single-machine].** See [[steam-networking]] — the wire seam + `L4STEAMNET` identity-token transport + `btl4lobby`. Live 2-account cross-machine session pending (`docs/STEAM_TEST.md`). - **Input-coverage audit + keyboard reconciliation: DONE 2026-07-20 [T2].** Root cause of the dead panel: `MechRIOMapper`'s message ids were chained one enum too high (0x19-0x2a) — the binary RIO table @0051dd30 re-registers the BASE aux/zoom ids 3..0x13 (Hotbox 0x1a); fixed ungated + static_assert-locked (`btl4mppr.hpp`) → all 24 MFD-bank + 2 zoom buttons live (52/72 panel buttons now work; 8 dead await handler reconstruction — Gitea backlog issue; 12 have no streamed mapping authored, authentically inert). **Keyboard = the ~20 core gameplay actions on the CONTROLS.MAP keys; the PANEL covers every pod address by click** (right-click = hold latch) — the merged default profile lives in `L4PADBINDINGS.cpp` (auto-writes `content\bindings.txt`; W/S/A/D/Q/E/R/F/X drive, 1-4/Space/Ctrl fire, M/N/H/C = pod buttons 0x18/0x15/0x2C/0x2F, `/V view toggle + J/K/L preset cycles hardcoded in PadRIO). Bound keys are SUPPRESSED from the typed 1995 channel (`PadRIO::SuppressKey`, the btinput pattern — ended the glass double-dispatch: 'w'=pilot-select, numpad/F-key key-up aliases); unbound keys keep their authentic meanings (5/z presets, t-o pilot select, +/- zoom). In BAS control mode the pod turns with the STICK (Q/E) and pedals are inactive — authentic; A/D turn in MID/ADV. Arrow keys mirror the drive cluster (UP/DOWN = the W/S throttle lever, LEFT/RIGHT = the A/D pedals). Full audit + census: `docs/GLASS_COCKPIT.md` §2026-07-20. - **2026-07-20 live "keymap regression" report: STALE EXE [T2].** The human-reported glass regressions (arrows/lever/detent dead, V/J/K/L/N inert, ground-fire) were a `build-glass/Release/btl4.exe` built BEFORE 5dd3536 landed — relaunched without rebuilding. No input-code change was needed; a clean rebuild + full SendInput re-verification (lever holds + zero stop, MID turns, V toggle shot-pair, level boresight, pod smoke) closed every symptom, and V's edge is now [T2]. `BT_MPPR_TRACE` now prints mode/pedals/stick/turn/elev. Procedural rule: rebuild every live build dir after landing an input/engine commit. Detail: `docs/GLASS_COCKPIT.md` §2026-07-20 (later). - **2026-07-20 human re-test: GAIT DETENT ported to the PadRIO lever [T2].** The remaining "our detent is missing" (mixed walk/run mode + repeated accel sample) was the gait DEAD BAND ([[locomotion]]): the pod-build keyboard lever snaps out of the walk/run hysteresis band at key-rest (mech4.cpp GAIT DETENT), and the PadRIO throttle slew lacked it. Ported faithfully: mech4.cpp publishes the band in lever units (`gBTGaitDetentLo/Hi` seam, +0.002 engage margin), `L4PADRIO.cpp` applies the identical nearer-edge snap when no throttle slew key/pad axis is active. Verified: parks at 0.414/0.465 snap to 0.358/0.504 (band = demand 22.02-30.87), no at-rest sample in-band, exactly ONE up-shift + ONE down-shift clip across a full graduated sweep, zero-stop + pod build unaffected. Detail: `docs/GLASS_COCKPIT.md` §2026-07-20 (later still). ## Key Relationships - Extends: [[pod-hardware]] (RIO input path) · Uses: [[gauges-hud]] dev-gauge modes · Feeds: [[multiplayer]] (miniconsole hosting, Steam transport) · Build: [[build-and-run]]