#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>
This commit is contained in:
co-authored by
Claude Fable 5
parent
e69c0d7aa8
commit
f44be87ab2
@@ -44,11 +44,70 @@ exactly the two that produced the most reconstructions — the census finds the
|
||||
4. **`0x4af691-0x4af9cf` (707 B), heat|mechmppr boundary** — heat-family tail or mapper head.
|
||||
5. **`0x4bdd7b-0x4be078` (673 B), mechweap|btplayer boundary** — weapon-family virtuals.
|
||||
|
||||
## Systemic fix status
|
||||
- The inventory (`reference/decomp/GAP_CENSUS.md` + `gap_census.tsv`) is now the FIRST stop
|
||||
before any "absent from the binary/export" claim — see gotcha §20's checklist.
|
||||
- **Ghidra re-export** remains the second half: no local Ghidra install on this machine;
|
||||
`reference/ghidra_scripts/` (ExportAll.java etc.) are ready when one is available (or on
|
||||
Nick's machine). A re-export with current auto-analysis + forced disassembly of the 332
|
||||
discovered starts would convert most of the 90 KB to pseudocode. Until then: raw disasm
|
||||
per region, as practiced.
|
||||
## PART 2 — THE RE-EXPORT (same day, 2026-08-06): the dark map, cut in half
|
||||
Installed (no admin, project tool convention `%LOCALAPPDATA%t411-tools`, beside DXSDK/cmake):
|
||||
**JDK 21.0.12** + **Ghidra 12.1.2**. ⚠ Ghidra's launcher `.bat` expands `%JAVA_HOME%`
|
||||
UNQUOTED, so the space in the user profile ("Joe Laptop") kills it — the runner uses 8.3 SHORT
|
||||
paths (`JOELAP~1`, `BT411-~1`). Zips deleted after extract.
|
||||
|
||||
New tooling (committed, repeatable):
|
||||
- `reference/ghidra_scripts/ExportGaps.java` — keeps ExportAll's EXACT output contract (shard
|
||||
format, index columns) so every tool/grep/`@ADDR` citation still works, and adds the gap-fill
|
||||
pass first: force disassembly + `createFunction` at (a) E8 call targets outside any function,
|
||||
(b) data→code pointers at a plausible prologue, (c) the census's discovered starts — iterated
|
||||
to a fixpoint. Logs what it created to `gapfill_report.tsv`.
|
||||
- `tools/ghidra_reexport.sh` — headless runner (`reprocess` re-runs the script on the saved
|
||||
project without re-analysis). `tools/gapdiff.py` — scores any two censused exports.
|
||||
|
||||
**Results (`tools/gapdiff.py`):**
|
||||
| Metric | Before | After |
|
||||
|---|---|---|
|
||||
| Index coverage of .text | 87.3% | **93.5%** |
|
||||
| Dark REAL code | 90.4 KB | **40.8 KB** (−49.5 KB, **54.8% recovered**) |
|
||||
| Game-side dark (bt/ + bt_l4/) | 53.1 KB | **21.1 KB** (−32.0 KB) |
|
||||
| Dark regions | 428 | 321 |
|
||||
| Functions / pseudocode | 6,267 | **6,472** (+205, **0 decompile failures**) |
|
||||
Gap fill converged in 2 rounds (205 created: 195 from census starts, 6 call targets, 4 data
|
||||
pointers) covering 56.1 KB. Ghidra 12 auto-analysis alone also found 42 more than the old export.
|
||||
|
||||
**Every historically-bitten dark function now has pseudocode**, including `@0x4c05c4`
|
||||
VehicleDead — the function whose absence OPENED this issue — plus ToggleLamp `@0x4b838c`, the
|
||||
TakeDamage death tail, the master-perf region (crouch/myomers/posture), the myomer integrator,
|
||||
and the `btplayer` hole `@0x4c0904`.
|
||||
|
||||
### Validation: the re-export CONFIRMS this week's hand reconstructions
|
||||
The master-perf pseudocode matches the crouch transcription field-for-field —
|
||||
`param_1[0xfe]`=mapPosture(0x3f8), `[0xe6]`=duckState(0x398), `[0x161]`=squatCapable,
|
||||
`[0x1e7]`=myomerEffectiveness(0x79c), `[0x10]`=movementMode, the `player+0x25c` novice gate,
|
||||
`FUN_004a7fc4(2/3)`=SetLegAnimation sqd/squ, `FUN_004a4c54(8)+(1)`=ForceUpdate, the
|
||||
`+0x131` stability alarm, and the duckState clear. Independent confirmation of a raw-disasm
|
||||
reconstruction, and of the census method that found it.
|
||||
|
||||
### …and it caught one thing the raw-disasm pass MISSED (fixed same day)
|
||||
The hand pass stopped at `0x4aa0af`; the pseudocode tail carries an **airborne auto-rise**:
|
||||
`if ((mode == 3 || mode == 4) && legState == 1) → SetLegAnimation(3) + ForceUpdate(8)+(1) +
|
||||
stability 1` — a mech that leaves the ground while parked in the squat is forced up,
|
||||
unconditional on duckState/squatCapable. Now in `mech4.cpp`; crouch re-benched un-regressed.
|
||||
|
||||
## Promotion + archive
|
||||
The re-export is now the CANONICAL `reference/decomp/` (index, shards, vtables, census). The
|
||||
previous export is preserved verbatim at **`reference/decomp/archive_2025export/`** so older
|
||||
KB citations of the form `part_0NN.c:LINE` stay resolvable — ⚠ **line numbers and shard
|
||||
membership shifted** in the new export (addresses did not). Cite `@ADDR` (stable), not
|
||||
part/line, going forward.
|
||||
|
||||
## Remaining dark (40.8 KB) — the next leads
|
||||
- `0x480a2a-0x487ca0` (~9 KB, l4splr|btmssn boundary) — still dark even after the fill: no call
|
||||
or data reference reaches it, which itself is informative (dead code? data misparsed as code?
|
||||
a jump-table-only region?). Worth a targeted look with the census's byte-scan.
|
||||
- New from the re-export: **`@0x4c0904` is the MASTER BTPlayer Performance** — team resolution
|
||||
by name ("Team ... does not exist"), the mission-end "Sending EndMission" console post, and
|
||||
the periodic console score heartbeat (corroborating our hand-built one). Our port attributes
|
||||
`@0x4c083c` as PlayerSimulation; that attribution needs a re-check.
|
||||
- The remaining munga/munga_l4 dark (~19 KB) is low priority — we compile the real engine source.
|
||||
|
||||
## Systemic fix status — BOTH HALVES DONE
|
||||
Inventory + re-export shipped. Rule (gotcha §20) stands and is now cheap to obey: check
|
||||
`GAP_CENSUS.md` before any "absent from the export" claim; if still dark, byte-scan.
|
||||
Re-run after any future re-export: `tools/ghidra_reexport.sh` → `tools/gapcensus.py` →
|
||||
`tools/gapdiff.py`.
|
||||
|
||||
Reference in New Issue
Block a user