Commit Graph
3 Commits
Author SHA1 Message Date
arcattackandClaude Fable 5 6bb03aed0b Gitea #48 ROOT-CAUSED + FIXED: MFD "stray blocks / misplaced lamps" = uninitialized translation-table entries leaking pixels into other displays' bit-planes
The conviction was empirical, not theoretical: a new write-site trap
(BT_PLANE_AUDIT) in the seven L4VB16 drawing primitives logs any draw whose
color carries bits outside its port's plane mask -- the exact cross-display
corruption condition (Replace ORs an unmasked color; Or/Xor ignore the mask
entirely; And clears foreign planes).  A quiet solo session produced 15-30
leaks per minute:

    [plane] PORT 'sec' pixmap draw at(0,0) idx 217 entry=0xffffff00 mask=0x3f
    [plane] LEAK DrawPixelMap8[table] at(639,0) color=0xffffff00 mask=0x3f leak=0xff00

THE DEFECT: L4GraphicsPort::translationTable[256] is never initialized in the
ctor, and BuildSecondaryTranslation fills only the entries its BitWrangler
reaches -- 2^numberOfBits: 64 for the sec plane (mask 0x3F), 4 for the overlay
(0xC0).  Entries above that stay heap garbage.  Every draw resolves color
through this table, and the PIXMAP path indexes it with raw pixel values
0..255: the 480x640 radar background carries pixel index 217, whose garbage
entry's high bits (0xFF00 = ALL EIGHT MFD planes) were stamped into the shared
640x480 buffer -- invisible on the culprit page (the in-plane bits happened
dark) and visible as bright fragments at the same coordinates on every OTHER
display.  That is the operator's screenshot exactly: the same-position blips
on Mfd1+Mfd2 and the Heat-display block.

FIX (engine, both layers):
  * zero translationTable in the L4GraphicsPort ctor (plane-neutral default);
  * BuildSecondaryTranslation now cycles the in-plane pattern across entries
    [2^bits..255] -- high-index art degrades to its (index mod 2^bits) colour
    IN-PLANE and can never leak.  The 1995 binary ships the SAME 64-entry fill
    and survived on 6-bit art discipline; garbage is not a preservable
    behaviour, so the cycle-fill is a guarded PORT deviation (documented).

A/B PROOF: same probe, 60s -- 0 leaks after the fix (15-30/min before).
sim3 3-pod regression: zero crashes.

SECOND real defect found + fixed en route: sessions configure the CAMERA seat
first ("cameraInit" -- which includes the MISSION-REVIEW context:
configure(0, sec, 0, 0x00FF, native, rgb, mrpal.pcc), a DirectColor context
whose translation tables legitimately hold full RGB565 values spanning all 16
plane bits), and the viewpoint swap to the mech re-configured WITHOUT tearing
that tree down (btl4app's s_gaugeTreeBuilt latch treats the mech build as the
first).  The orphaned review gauges kept executing through stale DirectColor
ports.  BTL4GaugeRenderer::ConfigureForModel now overrides (ConfigureForModel
made virtual in L4GREND.h) and tears the prior entity-bound tree down before
every rebuild -- safe on first build, and the review screen rebuilds the same
way when the seat returns to the camera.

Also logged (open-questions): the review-screen PlayerStatus panels read the
compiled player at RAW BINARY OFFSETS (+0x1FC vehicle / +0x1C8 score /
+0x1C4 alive-dead box) -- the databinding trap, dormant until the review
screen runs; bridge before enabling the review.

Ruled out along the way (with evidence): the pilot-list label/erase geometry
(erase box 128x32 covers the 64x16 name rasters), the radar name labels
(view-level ClipImage clips them), PlayerStatus in-game execution ([ps] probe:
never runs in-game), and the PNAME bitmap dimensions (egg generator emits
64x16 exactly).

Why it "started with the comms feature" (#43): that wave registered the new
gauge classes with the config interpreter, letting more of the authored page
furniture parse and draw than before -- the leaking high-index pixmaps rode in
with it.  [T3 correlation detail; the leak + fix are T2 live-verified.]

Diagnostics kept (env-gated): BT_PLANE_AUDIT (the leak trap, now a permanent
regression tripwire), BT_PS_LOG, the port-level pixmap identity trap.

KB: gauges-hud.md (#48 section), decomp-reference.md (BT_PLANE_AUDIT),
open-questions.md (PlayerStatus databinding entry).  checkctx CLEAN.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 17:20:19 -05:00
arcattackandClaude Fable 5 0d032029a0 Fix 2 (Gitea #12): gauge tree survives the in-session mech re-stream
The pre-launch host drop/rejoin re-stream re-creates every mech at mission
launch; the LOBBY-built gauge tree kept attribute pointers into the freed
first-stream mechs, every widget Execute AV'd, and the BT_DEV_GAUGES SEH
guard (Gauge::GuardedExecute, GAUGE.cpp:618) disabled each one PERMANENTLY
(rate=0, no rebind) -- the frozen dev-gauges window of incident #12.  The
authentic engine flow only tears the tree down at mission transitions
(Application::Shutdown -> gaugeRenderer->Shutdown() -> ShutdownImplementation
-> Remove(0), APP.cpp:787 / GAUGREND.cpp:3264); the re-stream bypassed it.

Fix: BTL4GaugeRenderer::TearDownForViewpointRestream() performs the
ENTITY-BOUND half of that same ShutdownImplementation sequence, in order
(gaugeAlarmManager->RemoveAllAlarms() -> Remove(0) -> moving/static entity
grid Clear), keeping the mission-scoped state (warehouse, graphics ports,
interpreter, controls-owned L4Lamps -- RemoveAllLamps would delete them
behind the buttonGroup's &lamp->automaticValue registrations).  Called from
BTL4Application::MakeViewpointEntity before ConfigureForModel("Init") on any
viewpoint RE-make -- that handler runs once per stream (the incident log's
[ctrlmap] installing x2) -- so the tree rebuilds bound to the NEW mech via
the renderer's existing lazy build.  Sentinel: "[gauge] viewpoint re-stream:
tearing the gauge tree down for rebuild".

Verified with the 2-instance relay harness (port 15600, MP_RELAY.EGG,
the incident sequence): join A (dev gauges) + B, kill B by exact PID at
WAITING FOR OPERATOR LAUNCH, rejoin B, operator launch.  Pod A re-streamed
(2x ctrlmap install, 4x zonebuild), logged the sentinel, and post-launch the
docked composite is fully live (mission clock/heading/radar advancing between
BT_SHOT frames) with ZERO [gauge-fault] DISABLED lines (the incident had 11).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 23:30:43 -05:00
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 21:03:40 -05:00