--- id: reconstruction-method title: "Reconstruction Method — the loop, the no-stand-ins rule, decomp technique" status: established source_sections: "PROGRESS_LOG.md §10b, §5a (decompilation), §10c" related_topics: [reconstruction-gotchas, decomp-reference, source-completeness] key_terms: [decomp, oracle, bridge, BTL4OPT, WinTesla] --- # Reconstruction Method How the missing BT game logic is rebuilt from the binary. The governing rule: **no stand-ins.** Full detail: `docs/PROGRESS_LOG.md §10b`; the systemic bug classes are [[reconstruction-gotchas]]. ## The loop (per feature) 1. Read the RAW decomp `reference/decomp/all/part_*.c` for the relevant `FUN_xxxx`. 2. Map `FUN_`/`DAT_`/`this+0xNN` to engine symbols using: the BT headers + the WinTesla MUNGA source + `game/reconstructed/CLASSMAP.md` + **RP's parallel code** (VTV≈mech, WEAPSYS≈weapons). 3. Write the **real** reconstruction into `game/reconstructed/*.cpp`. 4. Build; run env-gated; read `btl4.log` (grep `[anim]/[drive]/[target]/[fire]/[damage]` markers). 5. cdb on any crash. `static_assert`-lock the layout against the binary's offsets. [T2] ## RULE: no stand-ins The full game logic IS in the pseudocode (the binary ran the game); a "gap" is a reconstruction stub not yet filled, not a hole in the original. **Never write stand-in/placeholder logic for an apparent gap — read the decomp.** (User: "there are no gaps, just work to be done.") Bring-up scaffolding (env-var paths, explosion-for-beam, a player-gated drive) is clearly MARKED and meant to be REPLACED by the real reconstructed system, never to substitute for reading the decomp. [T2] ## Decompilation stack (Plan B — in progress) - **Ghidra 12.1.2 + JDK21** installed under `tools/` (portable). `ExportBTSource.java` run headless on `BTL4OPT.EXE` → real decompiled C in `reference/decomp/recovered/`. The pass is **assert-anchored** (few funcs/file — anchored on the asserts that carry source paths). [T2] - For a `FUN_` the assert-anchored exporter skipped: **`tools/disas2.py [len]`** (capstone disassembly of `BTL4OPT.EXE` — recovers x87 math Ghidra drops, folds known calls + float constants). Or `DecompVSS.java` (headless address-list decompiler). [T2] - **Resolving a `.data` fn-pointer** (a `PTR_LAB_xxxx` callback/vtable slot the decomp didn't export): PE-parse the DWORD at its VA, then capstone-disassemble the target. Used for the gait callbacks (`@0x4a6d8c`), the valve handler (`@0x4ae464`), gauge widget slots. [T2] - **`.data` float constants** are the biggest "couldn't recover" bucket (tuning values); read them as the x87 80-bit `float10` the decomp uses, not 32-bit float (`scratchpad/rdtbyte.py`). [T2] ## Effort model (honest) ~0.5-1.5 hr/module → ~30-50 agent-hours + human review for ~40 modules, with a long tail (modules with no surviving `.HPP` fragment, or split across decomp windows, cost more). Process upgrades: per-class function lists (not address clusters), complete vtable rows, recover `.data` constants. [T3] ## Workflows (for scale) For exhaustive multi-function decomp analysis, fan out a **read-only Workflow** (understanding phase — one agent per function/class produces an offset map + findings, + an adversarial verify), THEN implement hands-on so each change is visible + consistent. This is the §10c pattern; used for the ground-model decode (10 agents), the alarm-unification (8), the gauge-widget decode (6). [T2] ## Key Relationships - Bug classes: [[reconstruction-gotchas]] (check FIRST). Reference data: [[decomp-reference]]. - Why it's needed: [[source-completeness]].