Ported from RP412: RIOBase split out of the serial RIO (L4RIO.h), rioPointer is RIOBase* (L4CTRL.h), PAD token -> new PadRIO() speaking the RIO surface from an XInput pad + keyboard (L4PADRIO/L4PADBINDINGS, vRIO bindings.txt grammar, hot-plug), KeyLight RGB mirror TU (BT412KEYLIGHT, /std:c++17 per-file). BT-side fixes PadRIO forced into the open: - Both keyboard input bridges (mech4.cpp, mechmppr.cpp BT_KEY_BRIDGE) stand down when a RIO device exists -- they overwrote the engine controls push every frame. M/X conveniences stay live. - Mapper attribute chain OFF BY ONE (latent real-pod bug): the DOS chain below MechControlsMapper carried two base attributes, WinTesla carries one, and AttributeIndexSet::Find is positional -- the .CTL stick mapping wrote throttlePosition. Pad slot + binary-locked enum; gotcha ledgered (reconstruction-gotchas #11). Verified: PAD throttle lever ramps + sticks, stick turns with the authentic speed-vs-turn clamp (61.5 -> 22.0 u/s), mech drives; keyboard fallback intact (BT_FORCE_THROTTLE harness). New diags: BT_CTRLMAP_LOG, BT_STICK_LOG. (Phase 2 of docs/BT412-ROADMAP.md) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
132 lines
8.6 KiB
Markdown
132 lines
8.6 KiB
Markdown
---
|
||
id: steamification
|
||
title: "BT412 Steamification — status, seams, and merge notes"
|
||
status: living
|
||
source_sections: "docs/BT412-ROADMAP.md; RP412 repo (C:\\vwe\\RP412) git history + docs"
|
||
related_topics: [pod-hardware, multiplayer, gauges-hud, build-and-run, wintesla-port]
|
||
key_terms: [egg, RIO, console]
|
||
open_questions:
|
||
- "BT cockpit button-bank geometry source (no vRIO CockpitLayout exists for BT): l4gauge.cfg / pod photos / Nick"
|
||
- "Does BT's rebuilt L4D3D still have RP's NULL-texture AddRef crash pattern?"
|
||
- "Does L4CONTROLS=PAD set primaryControlType=PrimaryRIO so MechRIOMapper engages unchanged?"
|
||
---
|
||
# BT412 Steamification — status, seams, and merge notes
|
||
|
||
BT412 = BT411 made distributable on Steam and playable over the internet with no pod
|
||
hardware, following the recipe RP412 proved end-to-end (RP411 → RP412). The full plan
|
||
and phase order: `docs/BT412-ROADMAP.md`. RP412 (`C:\vwe\RP412`) is the reference
|
||
implementation — its git history from commit `467934c` onward is the steamification,
|
||
grouped roughly: toolchain → PadRIO input → MFD-split cockpit → front end/LocalConsole
|
||
→ NetTransport/Steam sockets → lobby → bindings/KeyLight → packaging.
|
||
|
||
**Repo rule [T0]:** `origin` = `VWE/BT412.git` only. This repo must never touch the
|
||
BT411 remote (no cross-pull remote — deliberate difference from RP412's `rp411`
|
||
pattern). Forked at BT411 `4e72f0c` (2026-07-14).
|
||
|
||
## Status ledger
|
||
|
||
- **Phase 0 bootstrap — DONE 2026-07-14.** Tree copied (working tree + full history,
|
||
`build/` excluded), origin re-pointed, fast-forwarded to `4e72f0c`, dev-state
|
||
`run/run.cmd` working-tree edit discarded (committed version is the documented solo
|
||
launcher), identity pass (README/CLAUDE.md/CMake `project(bt412)`), this topic +
|
||
roadmap authored.
|
||
- **Phase 1 (VS2022 v143) — DONE 2026-07-14.** Generator moved to
|
||
`Visual Studio 17 2022` (v143, Win32). One real change was forced: the v143 linker
|
||
fails the image on unresolved externals even under `/FORCE`, so the dead
|
||
offline-tool ladders in `game/reconstructed/mech3.cpp` are neutralized behind
|
||
`BT412_OFFLINE_TOOLS` (default off) and the exe now links `/FORCE:MULTIPLE`
|
||
(UNRESOLVED retired — real unresolved symbols are hard errors now). None of RP412's
|
||
other v143 source fixes (TIME.h, NETWORK.h, L4DINPUT, CAMMGR) were needed — BT's
|
||
tree was already v142-clean. Verified: clean build; solo DEV.EGG runs (gait/target/
|
||
31-subsystem ticks); two-instance loopback MP via btconsole.py — mesh forms
|
||
(console + 1502↔1602 game ports, "All connections completed!"), mission runs both
|
||
sides, each world ticks its master + the remote replicant. [T2]
|
||
- **Phase 2 (PadRIO input layer) — DONE 2026-07-14.** Ported from RP412:
|
||
`L4RIO.h` (RIOBase split; serial RIO re-parented), `L4CTRL.h` (`rioPointer` is
|
||
`RIOBase*`), `L4CTRL.cpp` PAD-token hook (→ `primaryControlType=PrimaryRIO`, so the
|
||
stock `MechRIOMapper` engages — confirmed), new `L4PADRIO.*` / `L4PADBINDINGS.*` /
|
||
`L4KEYLIGHT.*` (gates renamed `BT412KEYLIGHT`; KeyLight TU builds `/std:c++17
|
||
/permissive-` per-file). Default `bindings.txt` = the shared Tesla board layout
|
||
(numpad flight, letter rows = MFD banks, F-keys = Secondary columns, joystick head
|
||
0x40-0x47 on Space/arrows/pad). `content/bindings.txt` is gitignored (written on
|
||
first PAD run).
|
||
**BT-side changes PadRIO forced:** (1) both keyboard input bridges (mech4.cpp write
|
||
of mapper attrs; mechmppr.cpp `BT_KEY_BRIDGE`) now stand down when a RIO device
|
||
exists (`bridge_controls->rioPointer != 0`) — they clobbered the engine push every
|
||
frame; M mode-cycle / X recenter conveniences stay live. (2) **the mapper attribute
|
||
chain was off by one** — see [[reconstruction-gotchas]] §11 (short-parent-chain
|
||
positional trap): the `.CTL` stick mapping wrote `throttlePosition`. Fixed with a
|
||
pad slot + binary-locked enum. This was a latent REAL-POD bug (Phase 8 would have
|
||
hit it).
|
||
Verified live: `L4CONTROLS=PAD` → throttle lever ramps (rate axis, sticky), stick
|
||
deflects (turnDemand=1 + the authentic speed-vs-turn clamp: 61.5→22.0 u/s while
|
||
turning), mech drives across the map, XInput pad detected + 3 s re-probe, bindings
|
||
parse (59 key buttons/8 axes/12 pad buttons/5 pad axes). Keyboard fallback
|
||
regression-verified headless (`BT_FORCE_THROTTLE=1` walks). New diagnostics:
|
||
`BT_CTRLMAP_LOG=1` (streamed-mapping dump), `BT_STICK_LOG=1` (RIO stick push trace).
|
||
- Phases 3–7: not started — see the roadmap.
|
||
|
||
## The seams (what plugs in where) [T0 unless noted]
|
||
|
||
- **Input**: `LBE4ControlsManager` PUSH model; `L4CTRL.cpp` parses `L4CONTROLS` tokens;
|
||
RP412 adds token `PAD` → `new PadRIO()` (a `RIOBase` implementation from
|
||
XInput+keyboard), and the stock RIO mapper runs against it unchanged. BT's mapper
|
||
selection: `btl4app.cpp MakeViewpointEntity` switch on
|
||
`controls->primaryControlType` (+0xc98) → `MechRIOMapper` for PrimaryRIO(4).
|
||
- **Plasma**: BT's plasma is identical hardware to RP's (128×32, `L4PLASMA.h`);
|
||
RP412's `PlasmaScreen` renders the same `Video8BitBuffered` surface into a desktop
|
||
window, selected in `L4GREND.cpp` on `L4PLASMA=SCREEN`.
|
||
- **Displays**: BT pod = main 800×600 3D view + 640×480 radar + five mono MFDs on one
|
||
spanned 1280×480 surface (+ plasma). All cockpit surfaces are bit-plane masks over
|
||
one shared `SVGA16` pixelBuffer (see [[gauges-hud]], [[pod-hardware]]). RP412's
|
||
`MFDSplitView` (`L4MFDVIEW.*` + `L4VB16.cpp` split mode, `L4MFDSPLIT=1`) composes
|
||
child panes on a fixed 1920×1080 canvas; 3D presents into the viewscreen pane via
|
||
`Present(hDestWindowOverride)`.
|
||
- **Networking**: arcade stack unchanged (see [[multiplayer]]); RP412 moved the wire
|
||
behind `NetTransport` (`L4NETTRANSPORT.*`), default `WinsockNetTransport`, Steam
|
||
implementation `L4STEAMTRANSPORT.*` (`ISteamNetworkingSockets`, FakeIP + SDR,
|
||
degrade-to-TCP on any failure). Addresses stay SOCKADDR_IN-shaped so the egg
|
||
`[pilots] ip[:port]` roster works over both wires.
|
||
- **Session**: console protocol (egg msgID 3, 1040-byte chunks + ACK; RunMission
|
||
msgID 5 ×2; console must stay connected) — `tools/btconsole.py` is the working
|
||
feeder and the spec for the in-process LocalConsole marshal (Phase 5).
|
||
|
||
## Known merge risks (from the 3-way BT411 / RP411-baseline / RP412 comparison)
|
||
|
||
**Quantified 2026-07-14 [T1]** — BT-vs-RP411-baseline divergence measured with
|
||
`diff --strip-trailing-cr` (baseline extracted from RP412 history, `git show
|
||
3b8b729:MUNGA_L4/<f>`); RP412-side change sizes from `git diff 3b8b729..HEAD`:
|
||
|
||
| File | BT vs baseline | RP412 change | Treatment |
|
||
|------|----------------|--------------|-----------|
|
||
| `L4RIO.h` | identical | 125 lines (RIOBase split) | RP412 verbatim |
|
||
| `L4RIO.cpp` | identical | 0 | nothing to do |
|
||
| `L4CTRL.h`, `L4NET.H`, `L4PLASMA.*`, `L4KEYBD.h` | identical | small | RP412 verbatim |
|
||
| `L4CTRL.cpp` | 29 diff lines | 17 (PadRIO hook) | apply RP412 diff |
|
||
| `L4GREND.cpp` | 6 diff lines | 15 (PlasmaScreen selector) | apply RP412 diff |
|
||
| `L4VIDEO.cpp` | **2725** diff lines (BT render work) | only 14 | apply RP412 diff — small despite BT divergence |
|
||
| `L4VIDEO.h` | 29 diff lines | 7 | apply RP412 diff |
|
||
| `L4NET.CPP` | 23 diff lines (BT_NET_TRACE ×5) | 345 (seam refactor) | **MEDIUM** — apply seam refactor, re-site traces |
|
||
| `L4VB16.cpp` | **514** diff lines (dev-gauge dock) | 350 (split view) | **HIGH** — true hand-merge |
|
||
| `L4VB16.h` | 14 diff lines | 32 | hand-merge with L4VB16.cpp |
|
||
|
||
- **`L4VB16.cpp` — HIGH.** RP412 rebuilt ~3846–4046 (splitViews/canvas/present); BT
|
||
rebuilt the same window-management region for dev-gauge docking (`BT_DEV_GAUGES`,
|
||
`BT_DEV_GAUGES_WINDOW`, `BT_DEV_GAUGES_DOCK`, `BT_GAUGE_SCALE`, `BT_GAUGE_SEC_ROT`,
|
||
`BT_ALL` — 15 sites). Hand-merge; write the 3-way diff notes HERE before editing.
|
||
- **`L4NET.CPP` — MEDIUM.** RP412 rerouted all ~22–26 Winsock call sites through
|
||
`NetTransport_Get()`; BT's 5 `BT_NET_TRACE` diagnostic blocks sit exactly on those
|
||
send/receive sites and must be re-sited onto the seam calls.
|
||
- **CMake**: engine sources are explicit per-file lines (no globs) — every ported
|
||
`.cpp` needs its own `add_library` line or it silently doesn't compile. New deps:
|
||
`xinput9_1_0.lib` (PadRIO), C++/WinRT (KeyLight, per-file C++17), Steamworks SDK +
|
||
`steam_api.lib` behind `option(BT412_STEAM)`.
|
||
- **No `/Zp1` in BT's build** (RP's engine builds `/Zp1`): RP412's packing-mismatch
|
||
workarounds (`WINDOWS_IGNORE_PACKING_MISMATCH`, KeyLight default-packing carve-out,
|
||
`pack(push,8)` around Steam headers) are no-ops here — keep them for verbatim-ness,
|
||
but eyeball any copied code for /Zp1-layout assumptions.
|
||
|
||
## Key Relationships
|
||
- Uses: [[pod-hardware]] · [[multiplayer]] · [[gauges-hud]] · [[build-and-run]]
|
||
- Feeds: [[open-questions]] (steamification investigate items)
|