18 KiB
CRUSADER.EXE Hole-Filling Priorities From CRUSADER-RAW.EXE
Purpose
This note tracks the highest-value places where the NE-loaded CRUSADER.EXE project is still materially unclear, but the older CRUSADER-RAW.EXE project already holds enough verified structure to close the gap.
The goal is not to duplicate the raw notes. The goal is to rank the NE-side holes that are most likely to collapse quickly once the raw-side evidence is ported carefully.
Evidence used here:
- live Ghidra MCP checks in the open
CRUSADER.EXEsession plan-mid.mdcrusader_segment_coverage_ledger.csvdocs/raw-porting-progress.mddocs/raw-0007-rendering.mddocs/raw-0008-000c.mddocs/raw-000a-000d.mddocs/raw-000e.mddocs/crusader-disasm-reference.md
Priority 1: VM / USECODE Selector And Owner-Loaded Runtime Lane
Why it is still unclear in CRUSADER.EXE
- The NE project already carries the main structural names, but the actual upstream selector into the VM sequencer is still unresolved.
- The dark wrappers around slot
0x0a/0x0bare named structurally, not behaviorally. - The owner-resource helper is partially understood, but the exact class-family selection and configured owner-file naming are still open.
- Coverage ledger state is still only
Partialfor segments133,134, and135.
What the raw project already knows
000d:463ais now a verified generic masked-create hub:entity_vm_context_try_create_masked_for_entity.000d:45c5is a three-way category mapper:entity_vm_slot_index_from_entity.000d:4c99and000d:7000classify the runtime bootstrap and owner-resource creation path.000d:ebe3is a verified ordered opcode sequencer:entity_vm_opcode_sequence_run.0005:2c35is already narrowed toentity_vm_context_try_create_mask_0400_slot0a_with_offset, but its outward caller role is still dark.- The raw-side docs also already carry the exact
NPCTRIG/EVENTbody-window fits, referent-registry model, and the current selector blocker. docs/crusader-disasm-reference.mdalready identifies the best auxiliary corpus for this lane:usecode_opcodes.txt,map-item-dump.txt,shapedata_more_complete.txt, and theunkcoffs/dumps.
Porting work that should close the gap
- Port the raw-side selector, context, and owner-loader comments into the NE project at the same segment:offset anchors.
- Keep the slot-
0x0a/ slot-0x0bwrappers conservative until real caller roles are recovered. - Use the external opcode list and map/shape corpus only as hint generators while reconciling the live NE caller path.
- Prioritize recovery of the first caller that turns the category spans from
000d:45c5into a concrete class-family choice.
Live anchors in the open NE project
000d:45c5->entity_vm_slot_index_from_entity000d:463a->entity_vm_context_try_create_masked_for_entity000d:4c99->entity_vm_runtime_create000d:ebe3->entity_vm_opcode_sequence_run0005:2c35->entity_vm_context_try_create_mask_0400_slot0a_with_offset
Latest verified NE pass
0005:295fis now the only recovered non-hub consumer ofentity_vm_slot_index_from_entityin the open NE session. It recomputes the slot index, tests owner-row bit0x0040directly, exposes that result to the caller, and only then optionally callsentity_vm_context_try_create_masked_for_entitywith slot0x06and mask0x0040.- The direct NE callers currently recovered for
0005:295fare still only0006:43c3,0006:c5f0, and0007:3584, but they are now all structurally classified in the live NE session instead of only enumerated as open caller families. - The first anchored caller family is now structurally classified in the live NE session. Repaired wrapper
0006:4379is a seg031 dispatch-entry subtype gate over objects built by0006:42d9: event type0x236, source type8, subtype/tag at+0x3c, dword payload/source far pointer at+0x32, and aux words at+0x36/+0x38. - In that wrapper, subtype
0x20cat0006:43c3routes into0005:295f, while nearby sibling subtype0x20bat0006:43e5routes into0005:2918(slot 0x05/mask 0x0020) using the same+0x36/+0x38aux pair. The split is therefore local to one dispatch-entry family, not a direct compiledNPCTRIG/EVENTclass-family selector by itself. - The
0006:43c3lane now shows where the owner-row bit-0x0040probe is consumed locally: inside a subtype-0x20cdispatch-entry object rather than at a generic descriptor-choice site. That improves caller provenance for0005:295f, but it still does not prove which owner-loaded class family seeded the later VM data. - The second direct caller family is now closed too. Old
0006:c5f0lands at live call site1128:0ff0insideItem_ReceiveHit, where the non-NPC item path callsItem_GetDamagedwith hitter sentinel0x4000, packed damage(damagetype << 8) | damage_lo, and a local flag-out byte that records the returned owner-row bit-0x0040capability before the local destruction / impact follow-up. - The third direct caller family is now closed too. Old
0007:3584lands at live call site1138:1384insideSuperSprite_HitAndFinish, where the non-NPC collision lane probesItem_GetDamagedwith hitter sentinel0x4000and packed damage(firetype << 8) | damage; only when that flag-out byte stays clear and the target is not fixed does the lane fall through into the localItem_ReceiveHitknockback path. - The next earlier compiled-side producer is now closed for one real gameplay family.
AreaSearch_CollideMoveat10e0:123aqueues paired0x236storage processes in both its first-collision and linked-list collision lanes:0x20bis always created as the localhitnotifier from moving item to collided item, and the reciprocal0x20cprocess is always created as thegot-hitnotifier from collided item back to the moving item. - The local queue-helper cluster around that producer is now named in the live NE database too:
10f0:046d=storage_process_ref_list_create,10f0:0502=storage_process_ref_list_append, and10f0:06b5=storage_process_ref_list_destroy. Their recovered contract is a counted far-pointer array drained later byStorageDataProcess_RunAndTerminateProcs, not a darker allocator or owner-resource helper. - The producer surface above
AreaSearch_CollideMoveis now wider but still collision-local. Direct callers currently verified in the live session areItem_LegalMoveToPoint,Item_LegalMoveToPointWithCollisionInfo(10a0:1841),GravityProcess_Run,AnimPrimitive_CheckToStartNewAnimation,AnimPrimitiveProcess_Run,SuperSprite_AdvanceFrame, andGravityProcess_FastAreaCleanup(1038:11fd). No non-collision caller currently reachesStorageDataProcess_CreateorStorageDataProcess_RunAndTerminateProcsdirectly. - Two more local movement helpers are now named structurally in the live NE database:
10a0:1841=Item_LegalMoveToPointWithCollisionInfo, a legal-move wrapper that preserves blocked/collision outputs around the sameAreaSearch_CollideMovecommit path, and1138:0ee8=SuperSprite_SweepTestAdvance, the supersprite-side sweep probe that stores the first collision beforeSuperSprite_AdvanceFramecommits the move. - The surrounding movement and cleanup helper layer is now less anonymous too.
10e0:11c5=AreaSearch_SweepShapeBetweenPoints,10e0:15b4=AreaSearch_SweepItemToPointWithStepUp, and10e0:162f=AreaSearch_SweepShapeBetweenPointsWithStepUpnow cover the step-aware sweep path beneath the legal-move wrappers, while10f0:03ff=StorageDataProcess_Releaseand10f0:0542=storage_process_ref_list_terminate_item_matchesclose the local queue-release side. Adjacent seg090 helper10a0:196fis nowItemCache_PushAndPopToDirectionalOffset. 0005:2c35remains outward-dark in the current NE session: instruction search still shows no recovered code or data xrefs, and its proven local role is still onlysign-extended additive word -> slot 0x0a / mask 0x0400 -> generic masked hub.- The live
CRUSADER.EXEintegration batch is now extended for this lane. Comment-backed anchors were already present at1420:0dc5(Item_GetUsecodeClassId),1420:0e3a(Usecode_ItemCallEvent),10a0:2718(Item_Hit),10a0:275f(Item_GetDamaged),10f0:02d9(StorageDataProcess_Create), and10f0:0379(StorageDataProcess_Run), with branch comments at10f0:03c3and10f0:03e5preserving the verified0x20c/0x20bsplit; this pass adds live comments at10e0:123a,10f0:046d,10f0:0502, and10f0:06b5and promotes the queue helpers to stable names. - Result of this pass: all currently recovered direct
0005:295fcaller families are now closed, and the current0x236storage-process producer surface is now mapped far enough to say something negative too: the queue remains collision-local in the current database and is reached through movement, gravity, animation, and supersprite area-search paths rather than through a broader owner-family selector. The next defensible NE step is therefore either an earlier policy/dispatch layer deciding when those movement lanes callAreaSearch_CollideMove, or the first real non-collision producer if one exists elsewhere.
Priority 2: Rendering / Camera / Tile-Visibility / Watch-Controller Lane
Why it is still unclear in CRUSADER.EXE
- The raw rendering/camera work is one of the strongest finished structural maps, but the NE ledger still shows only
Partialcoverage for the watch-controller lane (seg049) andNonefor several related render-heavy segments. - The exact controller-versus-watched-entity ownership label around
0x2bd8is still open. - The NE side still does not have the same whole-lane readability that the raw
0007rendering notes already provide.
What the raw project already knows
- The raw notes already define the draw-list node format, tile visibility pipeline, screen/global state, scroll/camera globals, and the watch-controller family.
0007:ba00,0007:ba45, and0007:baeaalready have conservative structural names and caller contracts in the raw project.- The coordinate-transform lane is also already documented in a way that can be reused safely for the NE segments that call into it.
Porting work that should close the gap
- Port the controller/object comments around
0x2bd8,0x2be0, and the scroll globals before attempting any more aggressive renames. - Carry the draw-list, tile-grid, and viewport/global names into the NE lane where the same DS globals and call shapes match.
- Use
map-item-dump.txtandshapedata_more_complete.txtto explain object-heavy camera/trigger placements only after the binary side matches the raw lane.
Evidence anchors
- Ledger:
seg049=Partial,seg053=None, multiple surrounding render-heavy segments remainNone - Raw-side anchor doc:
docs/raw-0007-rendering.md
Priority 3: Startup / Display Transition And Active-Hold Lane
Why it is still unclear in CRUSADER.EXE
- The NE startup/display lane is structurally strong, but one of the key bodies is still overlap-damaged.
000c:db68currently resolves tocursor_nav_update_and_dispatch, but boundary analysis still shows an obviously oversized body spanning000c:5b68 - 000c:ff1c.- The renderer-pair role at
0x8c5c/0x8c60and the exact higher-level label for some preset paths remain open.
What the raw project already knows
- The raw project already separates the seg126/127/136/137/138 transition helpers into a usable startup/display model.
- The
0x6828 + 0x40borrowed hold byte is already separated from the seg108-local0x4f38bit-0x40lane. - The fade-controller behavior and the shared break/hold state around
0x31a2are already documented tightly enough to guide NE cleanup.
Porting work that should close the gap
- Use the raw-side boundary and caller notes to split
000c:db68back into the real local helper bodies before promoting any more labels. - Port the hold-token provenance and the seg108-versus-seg136 separation comments into the NE database.
- Keep the remaining renderer-pair naming conservative until the overlap is repaired.
Live anchors in the open NE project
000c:db68->cursor_nav_update_and_dispatch- Boundary analysis for
000c:db40..000c:dc40still reportscursor_nav_update_and_dispatch @ 000c:db68 body 000c:5b68 - 000c:ff1c - Ledger:
seg126,seg127,seg136,seg137,seg138are all onlyPartial
Priority 4: 0x4588 Callback / Allocator / Palette Cleanup Lane
Why it is still unclear in CRUSADER.EXE
- Many helpers in this lane are already named in the NE project, but the actual subsystem identity of the
0x4588object is still unresolved. - The same blocker is repeated across the ledger for segments
80,82,91,95, and138, which means the NE project has structure but still lacks the final behavioral classification.
What the raw project already knows
- The raw project already has a stable lifecycle map for
runtime_callback_object_init_once,runtime_callback_object_teardown_once,allocator_phase_finalize_pass, andentity_cleanup_resources_and_dispatch. - The raw notes already constrain the video-state snapshot pair, one-time guards, vtable call slots, emitted payload pairs, and the relationship to the watch-controller release path.
Porting work that should close the gap
- Port field-level comments around
0x4588,0x4590,0x4594,0x4595,0x45a6, and the emitted payload pairs before attempting any subsystem rename. - Reconcile the raw callback emissions with the NE caller windows in segments
91,95, and138. - Only promote a behavior-level subsystem name once those emitted payload pairs and caller families converge in the NE project too.
Live anchors in the open NE project
000a:4913->runtime_callback_object_init_once0009:b1c3->allocator_phase_finalize_pass000d:9afd->entity_cleanup_resources_and_dispatch
Priority 5: Parser / RIFF / Animation Video-Subframe Lane
Why it is still unclear in CRUSADER.EXE
- The main parser and animation entrypoints are already named in the NE project, but the surrounding segment coverage is still weak.
- The ledger still shows
Nonefor the raw-000e-mapped segments99through103. 000e:ffb0is still only a positional function object and remains overlap-damaged.
What the raw project already knows
- The raw notes already define the parser cluster, RIFF chunk matching, animation ring-buffer model, and the audio/video split.
- The raw-side caller proof already ties
000e:ffb0to the00db/00dcvideo-frame lane paired withanim_load_audio_frame. - The raw notes also already separate the text-oriented parser usage from the binary owner-loaded USECODE lane.
Porting work that should close the gap
- Port the parser and animation comments into the NE segment windows that still show no formal coverage.
- Keep
000e:ffb0conservative, but import the raw-side comment that it is the unresolved video-side subframe loader for the00db/00dcchunk lane. - Normalize the segment-to-topic mapping for the
000erange in the NE coverage ledger once those comments are in place.
Live anchors in the open NE project
000e:2104->animation_start000e:3639->record_table_parse_buffer000e:ffb0->FUN_000e_ffb0- Boundary analysis for
000e:ff90..000f:00f0still reportsFUN_000e_ffb0 @ 000e:ffb0 body 000e:ffb0 - 000f:00e0
Priority 6: Gameplay / Input / Projectile Expansion Into Adjacent NE Lanes
Why it is still unclear in CRUSADER.EXE
- Segment
1itself is already deep, but the adjacent event/dispatch and targeting lanes are not equally complete. - The ledger still shows only
Partialcoverage forseg021andseg043even though the raw project already holds stronger gameplay-side anchors. - The old disasm corpus has shape and event-code evidence that can explain object-heavy gameplay lanes, but that evidence has not yet been turned into a disciplined NE crosswalk.
What the raw project already knows
- Verified raw imports already exist for
shot_entity_alloc,projectile_update_tick, and the rest of the main projectile chain. seg021already has a verified direct raw import anchor viaentity_count_by_type_a.- The external corpus adds key/event notes such as
CTRL-Q = 0x410and map-backed shape examples likeSTEAM2andSnapEgg. - The raw side also already narrowed the seg043 start-of-segment hole enough to reject the earlier bad mapping.
Porting work that should close the gap
- Extend from the already-verified gameplay names into adjacent NE dispatch/targeting callers only when the segment:offset and caller role match directly.
- Build one conservative shape-id / map-placement crosswalk for trigger-heavy or object-heavy gameplay lanes before promoting new names.
- Use the old key/event notes as lead generation only, not as direct rename authority.
Live anchors in the open NE project
0007:28ce->shot_entity_alloc0007:371d->projectile_update_tick0007:5a00has no current symbol- Boundary analysis for
0007:59e0..0007:5b40still reports0007:5a00as a candidate entry and keeps the earlier rejected mapping explicitly closed
Secondary Structural Gaps To Keep On The Tracker
These are real NE holes, but they are weaker old -> new closure candidates than the priorities above because the raw-side model is still not strong enough to drive safe naming by itself.
000b:2e00
- Still a high-traffic gap in the NE project.
- Live symbol lookup returns no symbol at
000b:2e00. - Boundary analysis for
000b:2de0..000b:3050shows a missing top-level entry at000b:2e00plus several later artificial subfunctions. - Keep it on the list, but do not treat it as the first raw-to-NE porting target.
Immediate Actions Justified Now
- Create and maintain this tracker document.
- Use it as the ranked starting point for the first focused
CRUSADER.EXEporting batch. - Avoid immediate new Ghidra renames in the listed holes unless a pass first repairs the overlapping function objects or recovers the missing callers.
- Conservative comments are justified before renames in the VM, transition, and animation lanes because the remaining uncertainty is mostly about caller provenance and boundaries, not about the already-known local contracts.
Progress Estimate Impact
This note still does not justify a headline percentage change by itself.
The plan-mid.md progress estimates should stay unchanged until one of these prioritized NE passes produces verified new symbol, boundary, or ledger promotions beyond this local caller-family classification.