Crusader_Decomp/plan-mid.md

203 lines
31 KiB
Markdown
Raw Normal View History

# Crusader Decompilation Mid-Project Plan
## Purpose
This file is the live mid-project tracker for the Crusader decompilation effort.
Keep it focused on:
1. current verified state,
2. active blockers,
3. next resume work,
4. and the remaining path to a reasonably complete decompilation.
Detailed completed analysis belongs in the files under `docs/`, not in this plan.
## Progress Snapshot
2026-04-08 00:03:10 +02:00
Latest verified batch: [docs/startup-map-patch-file.md](docs/startup-map-patch-file.md) now closes the long-standing startup string `Using map patch file.` tightly enough to stop treating it as a vague debug/status artifact. Current best read is that `Init_Everything` prints that line only when `static\fixed.dat` exists, and the later fixed-map cache path then prefers the loaded `static\fixed.dat` archive handle over the base `fixed.dat` handle for map/fixed-object reads. The remaining uncertainty in this lane is now narrow: whether any later consumer does a finer-grained fallback/merge than the first recovered chooser, not what the startup line is referring to in the first place.
2026-04-07 17:16:44 +02:00
Latest verified batch: [docs/psx/psx.md](docs/psx/psx.md), [docs/psx/map-rendering.md](docs/psx/map-rendering.md), [docs/psx/map-viewer-plan.md](docs/psx/map-viewer-plan.md), and [docs/psx/art-binding-recovery.md](docs/psx/art-binding-recovery.md) now tighten the PSX render-side model another step in both Ghidra and the viewer exporter. The earlier `DAT_800758d4` consumer finding remains intact and is still wired into the viewer-side cache path as explicit `companionExtents` metadata, but the bigger practical change in this batch is the first measured art-binding recovery pass for the viewer exporter: the PSX cache builder now treats large zero-block `DAT_800758d8` constructor-placement bands as inherited-art candidates, first via same-map `DAT_800758cc` script-signature donors and then via a constrained nearest-donor fallback inside the current `0x003e..0x0064` family. That rebuild moved the scene set from `58,262` fallback items / `1,714` bundle-mapped items to `25,038` fallback items / `34,938` bundle-mapped items, making early representative maps such as `0`, `9`, and `43` mostly real-art while leaving `map 104` and the remaining `0x0042` / `0x0055..0x0063` constructor-placement band as the clearest unresolved outliers. The practical remaining gap is therefore narrower now: not "why are most PSX scenes placeholders" but "what executable-backed alias/resource rule explains the remaining zero-block constructor-placement families without leaning on donor heuristics."
2026-04-05 18:27:09 +02:00
- Overall useful decompilation progress: about 58%
- Reasonable uncertainty band: about 55% to 63%
- Top 100 far-call target coverage: about 86%
- Segment spread with meaningful analysis: about 34% to 40%
- Tooling maturity for continued work: about 83%
### Why The Estimate Moved
- The NE `CRUSADER.EXE` database now has materially more named functions, better caller-role coverage, and broader comment-backed provenance than when this tracker was first drafted.
- The startup/display lane is no longer a top active section. Its outer ownership and control flow are stable enough that it should stay closed unless new caller evidence changes the model.
- The cheat/debug lane is also much tighter: the `jassica16` latch, the broader `-laurie` gate, the `~` runtime toggle, the F7-family overlays, the F10/Ctrl behavior, and the `0x410` CD-transfer-display branch are now separated well enough that this lane is mostly documentation and cleanup, not architecture recovery.
- The USECODE/VM lane has moved from broad structure guesses to a partial runtime model: core loader/runtime helpers are named, owner-loaded slot arithmetic is verified against extracted corpora, several masked-create helpers have real contracts, and the major remaining uncertainty is now the upstream selector/caller path rather than the storage format itself.
- The map-renderer crosswalk lane also removed a lot of lingering shape ambiguity by closing more controller/helper families directly from extracted corpora plus scene evidence.
- The combat-tactic data lane is also now materially tighter: `COMBAT.DAT` is no longer just a named-tactic hint source, but a documented bytecode archive with stable per-record names, verified block structure, a decoded shipped opcode subset, and a practical family-level behavior map for the `Dumb`, `Pivot`, `Advance`, `Careful`, marker-shuttle, and step-out-shoot tactics.
## Current Verified State
### Primary Tracking Assets
2026-04-05 18:27:09 +02:00
- `crusader_segment_coverage_ledger.csv` remains the main executable-wide coverage tracker and should be updated after each verified batch.
- `crusader_decompilation_notes.md` is an index, not the place for long-form analysis.
- `CRUSADER.EXE` remains the default live Ghidra target.
- Verified `CRUSADER-RAW.EXE` work remains a supporting evidence base for ports, naming provenance, and caller/context cross-checks.
### Strong Or Stable Areas
2026-04-05 18:27:09 +02:00
- seg001 gameplay/input/projectile work is stable enough to support verified raw-name ports into live NE work.
- The raw `0007` rendering/camera/tile-visibility lane has a strong structural map and now acts more as supporting evidence than as a primary unknown.
- The `0008` dispatch-helper and `000c` state/transition lanes have broad partial coverage, including enough caller-side structure to support practical NE naming work.
- The VM/USECODE lane now also has one earlier compiled-side producer anchored beyond the old direct `Item_GetDamaged` / `StorageDataProcess_Run` callers: `AreaSearch_CollideMove` is now verified as a paired `0x20b` / `0x20c` collision-process producer, and the local seg031 queue helpers are named structurally in the live database.
- That same collision-storage producer surface is now wider too: current direct callers are all movement/physics/animation-side (`Item_LegalMoveToPoint`, `Item_LegalMoveToPointWithCollisionInfo`, gravity, animation, supersprite, and fast-area gravity cleanup), and no verified non-collision producer reaches the `0x236` queue yet.
- The movement/collision lane is tighter at the helper level too: the step-aware seg029 sweep wrappers, the seg031 release-side queue cleanup pair, and the adjacent seg090 directional cache-offset helper are now named in the live database, so the remaining uncertainty in this lane sits earlier in caller policy rather than in the local helper layer.
- The startup/display lane is materially closed. Shared dispatch-entry ownership, seg126 file-backed control flow, seg127 fade control, and the surrounding palette/presentation helpers are now understood well enough that they should not stay in the live critical path.
- The cheat/debug lane is mostly closed at the behavior level. The secret-sequence matcher, broader cheat gates, F7 overlays, F10 modifier path, `Ctrl+L` location popup, `Ctrl+Q = 0x410` CD-transfer-display toggle, `-debug`, and `-laurie` are all separated far more cleanly than before.
- The hidden usecode-debugger lane is now structurally understood as a layered orphaned subsystem: seg109 UI pieces, seg1408 break-state helpers, and the seg1418 interpreter handoff are no longer conflated.
- The USECODE/VM lane now has a workable compiled-side model around `entity_vm_runtime_create`, `entity_vm_runtime_owner_resource_create`, `entity_vm_context_create_from_slot_index`, the masked-create hub at `000d:463a`, the persistence/load helpers, and the owner-loaded slot/value arithmetic.
- The owner-loaded body/range model is no longer speculative. Class-selection uses `class_id + 2`, header/subentry math matches extracted corpus output, and concrete body windows for `NPCTRIG`, `EVENT`, and related families are now verified.
- The map-renderer/documentation lane now has a stronger shape/controller crosswalk. Recent closures include `CRUMORPH`, `NPC_ONLY`, `WATCHNS`, `WATCHEW`, `CRYOBOX`, `CRAZYEW`, `CRAZYNS`, `VIDEOBOX`, `PANELEW`, `GENERATR`, and cross-game `DEATHBOX`, with viewer-side links kept conservative where actor-side state is still runtime-only.
- The command-line/startup lane is much tighter across both games: `-warp <mission> [x y z]`, `-mapoff`, `-egg`, startup teleporter selection, and the `-u` EUSECODE root override all now have practical behavior models instead of folklore-level descriptions.
2026-04-07 00:15:44 +02:00
- The PSX lane is no longer just side inventory. Retail/pre-alpha bundle loading, mission-briefing/passcode structure, the reduced-content pre-alpha disc, and now the retail map object's last projection stage all have dedicated notes and enough stable naming to support future targeted passes.
2026-04-05 18:27:09 +02:00
- The Remorse class-lift preparation lane now has a usable document cluster: overall plan, candidate inventory, endpoint spec, ABI constraints, family notes for `EntityDispatchEntry` and `SpriteNode`, a conservative `Entity` family split, a VM runtime/owner-resource layout note, a compatibility-header draft, and one grouped resume index.
- The same class-lift prep lane is now more execution-ready: the `0x4588` broker family has its own focused object note, the toolchain story has a dedicated fingerprint-evidence note, and there is now a concrete first-batch class-authoring checklist ready for the first MCP-backed namespace/struct/vtable pass.
2026-04-06 12:19:03 +02:00
- The live Remorse VM class-lift lane also recovered from a decompiler breakage in `Remorse::EntityVmRuntime::Create`: the root cause was a hidden-return-storage allocator helper signature at `1000:42e2`, `Create` now decompiles again, and the provisional `/Remorse/EntityVmSlotEntry` datatype now exists with the stable `+0x1e..+0x24` buffer-pair fields named.
- The live Remorse VM class-lift lane is tighter again: the old `UsecodeProcess_*` context lifecycle bodies at `1420:0eec`, `1420:10b6`, `1420:10da`, `1420:1162`, `1420:118f`, and `1420:1278` now live under `Remorse::EntityVmContext::{CreateFromSlotIndex, FreeBuffer, SyncGlobalValueAndDispatch, Destroy, Save, Load}`, with short raw `000d:` provenance comments preserved on each entry.
- The same VM class-lift lane tightened one step further through local PyGhidra fallback once the live `run_write_script(...)` route still returned `404 No context found for request`: `/Remorse/EntityVmContext` is now a real datatype, `entity_vm_slot_entry_create_or_clear` and `InitSlotOwnerBuffers` now carry `EntityVmSlotEntry *`, `AcquireSlotForEntity` now returns `EntityVmSlotEntry *`, and `InitSlots` / `ReleaseSlots` now take direct `EntityVmRuntime * this`.
- That pass also made the remaining blocker more precise: `Create` still cannot hold a fully typed far `this` without reintroducing hidden `__return_storage_ptr__` corruption, so it was restored to the verified split-word custom-storage signature instead of forcing a broken prettier form.
- Tooling follow-up from that same batch is now clearer too: live MCP read-only Python is usable when Ghidra starts with PyGhidra enabled, but write-side repairs still had to fall back to closed-project local PyGhidra because MCP does not yet expose a constrained live write-script or equivalent custom-storage edit path.
- The live VM class-lift lane tightened slightly again in-session: `1420:19fd Remorse::EntityVmRuntime::EnsureSlotChunkLoaded` now carries a real `EntityVmSlotEntry *` local for the acquired slot path, so the slot-entry cache tail fields decompile directly instead of through anonymous `undefined4` pairs.
- The matching MCP gap is also clearer now: the old `apply_class_layout` dry-run null failure no longer reproduces for `/Remorse/EntityVmContext`, but the real write path still behaves like the older storage-preserving build. Actual `apply_class_layout` and direct `set_function_this_type` calls on the context lifecycle methods still fail with `Storage size does not match data type size: 2`, and live `run_write_script(...)` still returns `404 No context found for request` even with explicit target selectors.
- Closing the GUI and dropping to the local PyGhidra fallback then landed the blocked context typing work cleanly: `CreateFromSlotIndex`, `FreeBuffer`, `SyncGlobalValueAndDispatch`, `Destroy`, `Save`, and `Load` now all carry `EntityVmContext * this` as their first parameter in `CRUSADER.EXE`, which confirms the newer dynamic-storage rewrite is sound even though the live MCP session still is not taking it.
- The next live verification pass tightened two details. First, the new checked-in storage-aware prototype endpoint still is not the build currently serving the active GUI session: direct live POSTs to `/set_function_prototype_storage` still answered with the legacy `set_function_prototype` failure body, and the alias route still returned `404 No context found for request`. Second, the direct callers of `CreateFromSlotIndex` still mostly consume the result as a base process object, so the current conservative `UsecodeProcess *` return should stay in place until the inheritance-aware datatype story is explicit.
2026-04-07 00:15:44 +02:00
- The refreshed live MCP build moved that forward materially: `set_function_prototype_storage(...)` now reaches the real storage-aware implementation in-session and the active-program `run_write_script(...)` path now executes instead of failing with `404`. The new blocker is narrower and more concrete: bare `stack:` offsets at `10` and above currently need `0x` prefixes to preserve the intended stack slots, `__cdecl16far` still normalizes to plain `__cdecl`, and `Create` still cannot collapse to a single `EntityVmRuntime * this` because the datatype itself still resolves to a 2-byte pointer size.
- The same live batch also tightened the slot-entry class model: `/Remorse/EntityVmSlotEntry` now carries `match_key_farptr`, `owner_chunk_count`, and `owner_data_base` in addition to the earlier owner-buffer and chunk-state tails, which makes `InitSlotOwnerBuffers`, `AcquireSlotForEntity`, and `EnsureSlotChunkLoaded` read more like object code and less like anonymous offset arithmetic.
- The next live batch tightened the adjacent helper map too: the old unnamed `1420:1d72`, `1420:1d8d`, and `1420:1e17` helpers are now `entity_vm_runtime_get_slot_chunk_ptr_at_offset`, `entity_vm_runtime_release_slot_chunk_ref`, and `entity_vm_runtime_try_unload_slot_chunk`, which makes the slot-entry lifecycle around load, refcount release, and conditional unload materially easier to navigate.
- The latest live batch turned that helper lane into a small shared record model: `/Remorse/EntityVmLoadedChunkRecord` now carries the stable `next_*`, `saved_chunk_*`, `slot_index`, and `chunk_index` anchors, `entity_vm_runtime_try_unload_slot_chunk` now takes `EntityVmLoadedChunkRecord *` and returns `byte` in `AL`, and `entity_vm_runtime_apply_to_matching_owner_rows` now iterates over a typed loaded-chunk record instead of anonymous stack-pair scratch state.
- The adjacent interpreter-side lane is slightly tighter too: local helper `1418:003c` is now `interpreter_pop_saved_farptr`, and the only verified `Interpreter_NextUsecodeOp` release path at `1418:3330` is commented as a save/restore boundary around `entity_vm_runtime_release_slot_chunk_ref` instead of being left as anonymous stack traffic.
- The live class-authoring state moved forward too: `Remorse::EntityVmSlotEntry` now exists as a real class owner in `CRUSADER.EXE`, `CreateOrClear` moved under it with an explicit `this` parameter and `AX` pointer return, and the runtime-local chunk helpers plus owner-row iterator/debug path now sit under `Remorse::EntityVmRuntime` instead of Global.
- The next live pass improved the runtime class surface further: `GetSlotChunkPtrAtOffset` now carries the recovered `runtime_farptr/slot_index/chunk_index/intra_chunk_offset` signature and still returns its far pointer in `DX:AX`, while `ApplyToMatchingOwnerRows` now carries the recovered `runtime_farptr/slot_index_filter/chunk_index_filter` signature and still returns its boolean in `AL`.
- The latest live pass removed the old runtime-wide 2-byte-`this` bottleneck for this cluster: `Create`, `InitSlots`, `ReleaseSlots`, `DebugDumpSlotMemory`, `ReleaseSlotChunkRef`, `GetSlotChunkPtrAtOffset`, `TryUnloadSlotChunk`, `ApplyToMatchingOwnerRows`, and `EnsureSlotChunkLoaded` now all accept an explicit 4-byte `EntityVmRuntime * this` through `/Remorse/EntityVmRuntime *32` custom storage in-session. The remaining live type gap is narrower again: exact `/Remorse/EntityVmSlotEntry *32` return/parameter typing still fails on `AcquireSlotForEntity` and `InitSlotOwnerBuffers`, so those positions are currently held as neutral `dword` placeholders instead of prettier but broken slot-entry pointer types.
- That slot-entry gap is now closed too, and the pointer cleanup widened beyond the runtime core: `AcquireSlotForEntity` now returns `EntityVmSlotEntry *32`, `InitSlotOwnerBuffers` now accepts `EntityVmSlotEntry *32`, `EntityVmOwnerResource::{Create,Destroy}` now carry explicit 4-byte `this`, and the simple `EntityVmContext` lifecycle methods now do the same. The main remaining VM signature outlier is `CreateFromSlotIndex`, whose argument pack still needs caller-side recovery rather than just pointer-width cleanup.
- The next family switch also landed: `Remorse::UsecodeDebuggerBreakState` now exists as a real class owner with a `0x2f2` provisional datatype plus a first method batch for construction, breakpoint gating, breakpoint table helpers, callstack helpers, and step-state helpers.
- That debugger batch is already tighter than the initial shell: `1408:01a5` is now verified as `BreakpointRemove`, `1408:02f5` is now verified as `CallstackPushFrame`, breakpoint entries are recovered as `0x0b` inline-name-plus-line records, and callstack entries are recovered as `0x15` inline-name-plus-three-dword records even though the trailing dword semantics remain open.
- The next pass landed the debugger struct rewrite in-session too: `/Remorse/UsecodeDebuggerBreakpointEntry`, `/Remorse/UsecodeDebuggerCallstackEntry`, and the updated `/Remorse/UsecodeDebuggerBreakState` array layout now exist live instead of only in notes, and the only verified `CallstackPushFrame` caller now narrows those three trailing dwords to `source_stream_target_farptr`, `current_frame_payload_farptr`, and still-neutral `aux_farptr`.
2026-04-08 00:03:10 +02:00
- The latest debugger class-lift pass closed two more bounded gaps without overpromoting semantics: `1408:0230` now lives under `Remorse::UsecodeDebuggerBreakState::BreakpointFindFirstForUnitAtOrAfterLine` as the breakpoint-table lower-bound helper for `(unit_name, line_number)` queries, and the retail vtable root at `1478:65ab` is now resolved enough to show that `MaybeBreakOnCurrentLine` dispatches slot 0 into a shipped no-op stub while slot 1 currently returns zero through a second inert method.
- The next debugger follow-up also closed the planned seg109 consumer pass: `13a0:0291` plus its helper `13a0:045c` now show that the current callstack entry's `+0x09` lane is a real source-stream cursor consumed byte-by-byte by the debugger formatter and that `+0x0d` is the paired current-frame payload context used for expression/watch rendering. The remaining open tail-field question is now mostly `aux_farptr`, not the first two dwords.
- That naming decision is now landed live rather than only in notes: `/Remorse/UsecodeDebuggerCallstackEntry` now names offset `+0x09` as `source_stream_cursor_farptr` with an in-session field comment, and `CallstackPushFrame` now carries the same parameter name in its signature. The debugger-family residue is therefore narrower again: mainly `aux_farptr`, plus whether the seg109 formatter helpers deserve stable names.
- The next planned pilot family also started for real: `Remorse::EntityDispatchEntry` now exists in-session with provisional `/Remorse/EntityDispatchEntryBase` and `/Remorse/EntityDispatchEntryVtable` datatypes, so this family is no longer just a note cluster. The remaining blocker is now concrete rather than vague: the current source note still points at older `0008:` / `000d:` anchors that are not yet ported back onto the live `CRUSADER.EXE` method objects, so the first base-method ownership move has to wait on that mapping step instead of being guessed.
- That mapping step is now partially closed too. The older `0008:ba00` base cluster ports into live `11e0:` by offset, and the first base-method batch now lives under `Remorse::EntityDispatchEntry`: `InitBase`, `SetSourceType`, `SetEventTypeChecked`, `SetGroupId`, `Unlink`, and `IncrementGroupId`. The next blocker on this family is therefore narrower again: not whether the pilot can move methods at all, but which live segments carry the remaining word-list, timed/periodic, and runtime-state methods from the older `0008:` / `000d:` notes.
- The runtime-state follow-up is now partially closed too. `FadeProcess_Create` is explicitly tagged by the decompiler as old `000d:7e00`, `FUN_1440_0278` matches the old `000d:8078` release path by both offset delta and behavior, and both now live under `Remorse::EntityDispatchEntry` as `InitRuntimeState` and `ReleaseRuntimeState` with a new `/Remorse/EntityDispatchEntryRuntimeState` overlay datatype. That leaves the remaining `EntityDispatchEntry` pilot work in a narrower end-of-day state: mainly the word-list destroy lane and the timed/periodic constructor cluster, not the core base or runtime-state surfaces.
2026-04-07 00:15:44 +02:00
- `CreateFromSlotIndex` is no longer a raw anonymous pack either: the live signature now separates `owner_source_farptr`, `pitemno_farptr`, `mode_flags`, `slot_index`, `value_add_offset`, `intra_chunk_offset`, `ucparam_farptr`, and `ucparamsize`, with explicit `AX:DX` return storage restored even though the endpoint still textualizes the function conservatively as plain `dword __cdecl`.
2026-04-05 18:27:09 +02:00
### Areas That Are No Longer Live Priorities
- Startup/display transition recovery is no longer a front-line blocker unless overlap repair becomes necessary for adjacent work.
- The general cheat/debug key matrix no longer needs broad exploratory work.
- The `-debug` switch is no longer an open mystery; remaining work there is mostly sink-side cleanup and documentation.
- The earlier executable-patch experiments around the hidden debugger are documented history, not a current decompilation priority unless new evidence changes the entry model.
## Live Blockers
2026-04-05 18:27:09 +02:00
1. The main remaining VM uncertainty is the real upstream selector/caller path into `entity_vm_opcode_sequence_run` and adjacent masked-create helpers. One earlier producer is now closed at `AreaSearch_CollideMove` for the `0x236` collision-storage family, but the owner-loaded class-family chooser and any broader non-collision producers are still upstream-dark.
2. The dark masked-materializer wrappers still need caller-role recovery, especially the signed-additive slot-`0x0a` / slot-`0x0b` pair and the surrounding higher-slot wrapper ladder.
3. The callback object rooted at `0x4588` still lacks a behaviorally safe subsystem name even though its allocation/finalize neighborhood is better constrained.
4. A few hot or awkward function ranges still lack clean function objects or good boundaries, especially around `000c:db68`, `000e:ffb0`, and several caller-dense gaps in `0007`, `000b`, and `000e`.
5. Weakly covered resource/data-loader families and non-`CALLF` far-pointer relocations are still a second-pass blocker for some object/table recovery work.
6. The segment ledger has improved, but it still trails the actual verified state in the notes and Ghidra database. Promoting known segments from documented evidence remains real work, not bookkeeping trivia.
## Current Focus
2026-04-05 18:27:09 +02:00
1. Keep the live NE `CRUSADER.EXE` lane as the default working surface, using raw/full-EXE and standalone-segment work only as supporting evidence.
2. Keep the VM/USECODE lane focused on selector recovery, caller-role recovery, and record-shape confirmation rather than repeating storage-format validation that is already closed.
3. Promote ledger coverage from existing verified notes before broadening into fresh executable-wide sweeps.
4. Use overlap repair only where it unlocks an active high-payoff lane.
5. Use the map-renderer/tooling lane to validate shape ids, map placements, and viewer semantics before promoting additional static-object names in Ghidra.
2026-04-07 17:16:44 +02:00
6. Keep the PSX lane focused on the final state/variant/art bridge now that the first post-spawn interaction/reselection cluster is named; avoid broad renderer-side heuristics that bypass those runtime paths.
## Next Resume Point
2026-04-05 18:27:09 +02:00
1. Resume from `docs/ne-hole-filling-priorities.md` and pick one small NE cluster where the old disasm vocabulary, extracted corpus evidence, and live NE callers overlap cleanly.
2. Stay on the VM lane and move one step earlier than the now-mapped movement/collision helper set around `AreaSearch_CollideMove`: the local seg029/031/090 helper layer is now named, so the next work is the policy/dispatch layer that decides when those legal-move, gravity, animation, or supersprite paths instantiate the local `0x236` collision-storage queue, plus verification of whether any non-collision producer feeds the same `StorageDataProcess_Create` / `Run` family.
3. Recover caller roles for the remaining dark signed-additive masked wrappers, especially the slot-`0x0a` / slot-`0x0b` pair, and compare them against the now-anchored slot-`0x12` caller pattern.
4. Tighten the higher-slot wrapper ladder around `0005:3115..31da` so future event-label promotion depends on compiled caller behavior instead of external tables.
5. Tighten the seg006 masked-helper caller chains so the local state-selector/value family can be tied to concrete gameplay subsystems.
6. Classify the paired seg070 loops behind `entity_vm_runtime_owner_resource_create`, especially which temporary buffers and record schemas each family populates.
2026-04-07 00:15:44 +02:00
7. Stay on the Remorse VM class-lift batch while the repaired runtime lane is warm: use the now-recovered `CreateFromSlotIndex` caller pack to decide whether any remaining scalar positions deserve stronger typedefs, but keep the return semantically conservative until the base-process inheritance model is explicit enough to justify a prettier live return type.
2026-04-08 00:03:10 +02:00
8. Continue the `UsecodeDebuggerBreakState` family from the now-landed live array layout, callback-map pass, seg109 consumer pass, and live datatype promotion only if the last `aux_farptr` lane can be closed cheaply; otherwise resume from the current `EntityDispatchEntry` stopping point and map the remaining old `0008:` method groups onto live `CRUSADER.EXE` segments, especially the word-list destroy lane and the timed/periodic constructor cluster.
2026-04-06 12:19:03 +02:00
8. In the local GhidraMCP upgrade lane, add support for dual POST body decoding (`application/json` plus form-urlencoded) and a constrained live write-side PyGhidra endpoint family so future custom-storage/type repairs can stay inside the active MCP session when Python is enabled.
9. Promote additional ledger rows directly from already-verified docs and live comments, especially where segments already deserve `Foothold`, `Partial`, or `Deep`; the new seg029 step-aware sweep batch, seg031 queue-release batch, and seg090 movement-helper batch should be the immediate template.
10. If the VM lane stalls, revisit `000e:ffb0` from the now-better-constrained video/audio caller windows and try to recover an adjacent non-overlapped helper before attempting broad boundary repair.
11. Continue the map-renderer cross-check lane by building one conservative shape-id/map-placement crosswalk from `shapedata_more_complete.txt`, extracted corpora, and authored scene evidence before promoting more trigger-heavy classes in NE.
12. Keep the PSX pre-alpha lane alive as a secondary target: classify the `LoadExec` callers, test whether the stale `TALK1.XA` path is still reachable, and compare the shipped `LSET1` bundles against the retail extractor outputs.
2026-04-07 17:16:44 +02:00
13. Continue the retail PSX state/art lane from the new art-binding recovery baseline: keep `DAT_800758d4` on the runtime-bounds side unless new family-specific evidence contradicts it, treat `map 104` plus the remaining `0x0042` / `0x0055..0x0063` zero-block constructor-placement band as the primary regression target, and trace the next family-specific callers around `psx_type4_reselect_motion_state`, `FUN_80028c94`, constructor-side resource creation, and the drawable-resource/frame submission lane until the remaining donor-based fallback logic can be replaced with an executable-backed alias/resource rule.
## Remaining Work To Reach A Reasonably Complete Decompilation State
### 1. Coverage And Tracker Completion
2026-04-05 18:27:09 +02:00
- Keep turning the seeded 145-row ledger into a trustworthy whole-program dashboard.
- Sweep remaining lightly covered segment clusters by adjacency and call relationships rather than one-off function hunting.
- Keep the plan, the docs, the ledger, and the live Ghidra comments synchronized after each verified batch.
2026-04-05 18:27:09 +02:00
### 2. VM / USECODE / Scripting Lane
2026-04-05 18:27:09 +02:00
- Close the upstream selector/caller path into the sequencer and masked-create families.
- Finish separating owner-row-backed data from runtime-decoded control streams and dispatch-entry seed records.
- Expand caller-backed event-label promotion only where binary behavior and slot reuse agree.
- Keep maturing the tooling bridge from extracted corpora into compiled-side annotation/import workflows.
2026-04-05 18:27:09 +02:00
### 3. Callback / Allocator / Object-Role Lane
2026-04-05 18:27:09 +02:00
- Classify the `0x4588` callback object strongly enough for a real subsystem name.
- Separate generic cache/allocator mechanics from game-specific client behavior where caller evidence supports it.
- Keep low-level helper names conservative until behavior, not just structure, is clear.
2026-04-05 18:27:09 +02:00
### 4. Rendering / Animation / UI Support Lanes
2026-04-05 18:27:09 +02:00
- Keep the rendering/palette/animation lanes focused on caller-side semantics and cleanup, not exploratory renaming in isolation.
- Revisit `000e:ffb0` and adjacent overlap-heavy video helpers only when the payoff is clear.
- Use map-renderer evidence and extracted corpora to validate static-object and helper/controller naming before promoting it into live NE work.
2026-04-05 18:27:09 +02:00
### 5. Data / Resource / Relocation Coverage
2026-04-05 18:27:09 +02:00
- Tackle deferred non-`CALLF` far-pointer relocations when they are needed for active table/object recovery.
- Broaden weakly covered resource/data-loader families where they block real subsystem classification.
- Keep external references like ScummVM or older disasm corpora as evidence aids, not rename authority.
## Priority Order
2026-04-05 18:27:09 +02:00
1. VM / USECODE selector and caller recovery
2. Coverage-ledger refinement from already-verified notes
3. Callback-object classification around `0x4588`
4. High-value boundary repair when it unlocks active work
5. Broader segment sweeps and second-pass data/relocation work
6. Secondary map-renderer and PSX follow-up lanes
## Evidence Anchors
Primary files backing this plan state:
- `crusader_segment_coverage_ledger.csv`
- `crusader_decompilation_notes.md`
- `docs/overview.md`
2026-04-05 18:27:09 +02:00
- `docs/ne-hole-filling-priorities.md`
- `docs/crusader-disasm-reference.md`
- `docs/raw-porting-progress.md`
- `docs/raw-0008-000c.md`
- `docs/raw-000a-000d.md`
- `docs/raw-000e.md`
- `docs/far-call-targets.md`
- `docs/usecode-roundtrip-ir.md`
## Update Rule
Update this file when one of the following happens:
- the headline estimate changes materially,
- a live blocker is resolved,
- a subsystem moves from structural to behavioral understanding,
- a segment cluster is promoted materially in the ledger,
- or the next resume point changes enough that the current handoff would mislead the next pass.
2026-04-05 18:27:09 +02:00
Keep this file short. Move detailed completed analysis into the appropriate file under `docs/` and leave only the current state, blockers, and forward path here.