38b08c96d1f94317e44a19d784526a8c2751b392
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f44be87ab2 |
#60 PART 2: the RE-EXPORT -- dark code 90KB -> 41KB, coverage 87.3% -> 93.5%
Installed JDK 21 + Ghidra 12.1.2 (no admin, %LOCALAPPDATA%\bt411-tools beside DXSDK/cmake; runner uses 8.3 SHORT paths because Ghidra's .bat expands %JAVA_HOME% unquoted and the profile has a space). New tooling: reference/ghidra_scripts/ExportGaps.java -- ExportAll's exact output contract PLUS a gap-fill pass (force disassembly + createFunction at E8 call targets outside functions, data->code pointers at a plausible prologue, and the census's discovered starts; iterated to a fixpoint, logged to gapfill_report.tsv). tools/ghidra_reexport.sh (headless runner, 'reprocess' mode) and tools/gapdiff.py (score two censused exports); gapcensus.py now censuses any export dir. Results: 6267 -> 6472 functions (+205 created in 2 rounds: 195 census starts, 6 call targets, 4 data pointers; 56.1KB newly covered), ZERO decompile failures. Dark real code 90.4 -> 40.8 KB (54.8% recovered); game-side dark 53.1 -> 21.1 KB; regions 428 -> 321. EVERY historically dark function now has pseudocode -- including @0x4c05c4 VehicleDead, the absence that opened this issue. VALIDATION: the new pseudocode confirms this week's hand reconstruction of the crouch field-for-field (mapPosture/duckState/squatCapable/myomerEff/ novice gate/SetLegAnimation/ForceUpdate/stability alarm) -- and exposed one branch the raw pass missed: AIRBORNE AUTO-RISE (mode 3|4 && legState 1 -> forced squ), now implemented in mech4.cpp and re-benched un-regressed. PROMOTION: the re-export is canonical reference/decomp/; the previous export is preserved at reference/decomp/archive_2025export/ so old `part_0NN.c:LINE` citations still resolve (addresses are stable across both; line/shard membership is NOT -- cite @ADDR). New lead recorded: @0x4c0904 is the MASTER BTPlayer Performance (team resolution, EndMission console post, score heartbeat) -- our @0x4c083c PlayerSimulation attribution needs a re-check. KB: source-completeness, gotcha #20 (the rule is cheap now -- look it up), CLAUDE.md router/layout. Log: phases/phase-04-gap-census.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e69c0d7aa8 |
#60 GAP CENSUS: the export dark-region inventory (tool + report + KB)
tools/gapcensus.py (deterministic): index-vs-.text interval math, export cross-check, function-start discovery inside dark regions (E8 call targets + data-section code pointers), pad exclusion, TU attribution, repo-citation flags. Output: reference/decomp/GAP_CENSUS.md + gap_census.tsv. Headline: .text 892KB, index covers 87.3%; 428 dark regions = 90KB REAL code (indexed-but-unexported = 0 -- the gap class is purely 'never indexed'). Game-side dark ~54KB: 66 regions visited by past digs, 159 NEVER TOUCHED. Validation: all six historically-bitten dark addresses (VehicleDead, ToggleLamp, death tail, master-perf, myomer integrator, duck consumer) land inside census regions; the two most-cited regions are the two that produced the most reconstructions. Top uncharted leads (spot-checked real code): the ~9KB l4splr|btmssn cluster (dispatch-table state machine -- likely BTMission's unexported heart); the 613B btplayer hole before the ctor (mission-review id-0x18 sender suspect); btl4app tails; heat|mechmppr + mechweap|btplayer boundaries. Full log: phases/phase-04-gap-census.md. Re-export half deferred (no local Ghidra; scripts ready). KB: source-completeness census section + CLAUDE.md lookup row + decomp-reference tools entry; consult the census BEFORE any 'absent from the export' claim (gotcha #20). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
29035028fd |
Cross-pod beams: replicate emitter discharge via subsystem update records
User report: lasers only visible on the window firing them. The peer's replicant emitters never learned the master fired. THE AUTHENTIC PIPE (decomp-verified): - FUN_0041c350 (the "beam keepalive" ServiceDischarge/ContinueDischarge call) does TWO things: queue the LOCAL deferred beam-effect callback (@0x4bac0c) on the app+0x34 manager -- our per-weapon render walk already plays that role -- and set the subsystem DIRTY bit, which maps to the 2007 engine's updateModel / ForceUpdate(). - Replication rides SUBSYSTEM UPDATE RECORDS inside the mech's update message: the roster walk already hands the entity's stream to every subsystem's PerformAndWatch; Simulation::WriteSimulationUpdate serializes each requested updateModel bit; Entity::UpdateMessageHandler routes received records by subsystemID to the subsystem's ReadUpdateRecord. All engine machinery -- the missing pieces were the Emitter's serialize/apply pair + the triggers. CORRECTIONS to the dormant task-33-era transcriptions (never exercised -- nothing ever set updateModel -- so the latent misreads never surfaced): - The weapon-family VTABLE SLOT MAP was swapped: slot 6 = ReadUpdateRecord, 7 = WriteUpdateRecord, 9 = TakeDamage (evidence: Mech hierarchy symmetry + body semantics; @004ba568 resolves an EntityID at rec+0x30 through the entity index -- record semantics, not Damage). Renamed across MechWeapon / Emitter / ProjectileWeapon; the real Emitter::TakeDamage @004bafc8 is undecoded (inherits MechWeapon for now). - Emitter/MechWeapon Write: `*record = 0x38/0x18` is the record LENGTH, not recordID; rec+0x30 is the TARGET's EntityID (GetEntityID()), not a colour -- the old `CopyColor(targetEntity+0x184)` was also a databinding trap. - OVERRIDE-SIGNATURE TRAP: the decls used each class's own shadowing UpdateRecord typedef as the param type, silently NOT overriding the engine virtual (the base ran instead; nothing would ever have serialized). Base-typed params (Simulation__UpdateRecord*), casts inside. - Emitter::ReadUpdateRecord reconstructed (@004ba568): target EntityID resolve (drop unknown non-null targets), MechWeapon alarm apply chain, beam fields. - ServiceDischarge/ContinueDischarge: ForceUpdate() per keepalive tick + one final record at beam end (turns the peer's beam off). - Mech::DrawWeaponBeams extracted from the player-only drive block so the walk runs for REPLICANTS (+ per-mech gun-port cache -- the process-wide statics would have served the player's segment pointers as the replicant's muzzles). VERIFIED 2-node: A fires 57 volleys -> 225 emitter records -> B applies all 225 -> B draws 414 beams (PPC blue / laser red, from A's replicant's own gun ports). Solo un-regressed (150 beams, kill chain, no crash). Also preserved: the full Mech::WriteUpdateRecord @0x4a0c2c recovery (reference/decomp/mech_writeupdate_004a0c2c.disasm.txt) with all 9 record types decoded (pose/alarm/leg-state+heat with the body-channel write-through re-sync, knockdown, death, impact, movementMode) -- transcription deferred; it replicates remote knockdown/death/heat and was not needed for beams. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
18d49491b7 |
Reticle Execute @004cdcf0 RECOVERED: every HUD instrument now live (task #37)
The one un-exported gap in the reticle chain, read via capstone (tools/disas2.py; the annotated disasm preserved at reference/decomp/reticle_execute_004cdcf0.disasm.txt). Draw() is now a transcription of the real per-frame logic, and the HUD attr-table names (hud.hpp ids 4/5/6/8/A/B/C/D) are CONFIRMED by their Execute usage: - Range ladder: BAR from ladder-top to the caret + caret translate. - The bottom 21-tick tape is the TORSO-TWIST indicator (NOT heading): deflection = -/+(span/2) x (RotationOfTorsoHorizontal / twist limit), attrs 4/5/6. Fixed-torso BLH reads centred -- authentic static. - The circle-with-stem is the COMPASS (attr 0xD, rad->deg rotation) at (botX, botY - 3*tickMajor - 0.03), with the THREAT trail (attr 0xC) in its rotated frame: 0.05-unit attack-direction marks, fresh < 2s red, expiring at 6s. Port feed: player TakeDamage pushes the impact direction (dormant vs the passive test dummy). - Pips (composed into subB6): hidden when destroyed (attr 1 == 1), LIT when the fire cycle is LOADED (attr 0x1c == 2; port source rechargeLevel >= 1) else the dark charging ring; filtered by the weapon-GROUP bits (weaponMode & elementMask&0xF). Range plays NO part (the stored TargetWithinRange slots are never read by Execute). - Lock ring: subB9 at frame centre SPINNING 4 deg/frame while locked ([0x9d] is the spin matrix, not a heading list). - Target HOTBOX: a rectangle hugging the projected extents (x+-4 around the top-centre hotbox point, +1/-11.5 vertical; baked K=2.8145 -- the port projects through the live per-axis projection), switching to the edge arrows past +-1.6 or behind (BTProjectHotBox, L4VIDEO). - Reticle state Off/On + PrimaryHudOn full-HUD/simple-X switch, aim translate on slew move, 3D marker + PNAME player-name mesh identified (chain still deferred). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
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>
|