Crusader_Decomp/docs/remorse-class-candidate-inventory.md

115 lines
12 KiB
Markdown
Raw Normal View History

2026-04-05 18:27:09 +02:00
# Remorse Class Candidate Inventory
## Purpose
This note is the working inventory for the first C++-oriented class lift in Remorse.
It is intentionally narrower than a full source plan. The goal here is to identify the object families that already have enough verified evidence to justify explicit class modeling in Ghidra later, even before the MCP layer grows class-authoring endpoints.
Until MCP can create namespaces, move methods, and build typed vtable/struct layouts directly, this note should act as the canonical queue for manual class-upgrade work.
## Selection Rules
A family belongs here only if at least some of the following are already true in the current notes:
- a constructor-style allocator/init path exists
- a destructor, teardown, or release path exists
- one or more stable vtable roots or slot dispatches are known
- instance fields have repeatable meanings across multiple methods
- the family has enough caller context to separate instance methods from generic helpers
Families that are only `callback-shaped` or `object-like` but still lack a safe subsystem label can stay here at lower confidence. They are still useful because they tell us where later class tooling must preserve ambiguity.
## Confidence Scale
- High: enough evidence to start class namespaces, instance structs, and method ownership now
- Medium: class-like enough to inventory and maybe type, but higher-level naming or ownership is still partially open
- Low: strong object mechanics, but subsystem naming or field ownership is still too ambiguous for broad lifting
## Inventory
| Candidate family | Confidence | Current best class-level read | Core evidence | Ctor / create evidence | Dtor / release evidence | Vtable evidence | Size / layout evidence | Immediate lift value |
|---|---|---|---|---|---|---|---|---|
| `EntityDispatchEntryBase` | High | Base dispatch-entry object used by scheduler/event and transition/runtime-state families | `entity_dispatch_entry_init`, repeated field writes, list ownership, flag/state helpers | `0008:ba00 entity_dispatch_entry_init` alloc/init path for `0x32` bytes; variant allocators in `0004:ea00`, `0008:cefb`, `0008:d214` | `0008:dbec entity_word_list_destroy`; `000d:8078 entity_dispatch_entry_release_runtime_state` for runtime-state flavor | base/root vtables `0x3b06`, `0x2d10`, `0x3afe`; derived vtables `0x3ad2`, `0x3aa6`; slot dispatch at `+0x14`, `+0x28` | stable fields at `+0x02`, `+0x04`, `+0x06`, `+0x08`, `+0x0a..+0x18`, `+0x32..+0x3e`, plus runtime-state tail | Strongest pilot family for the first full class-model pass |
| `EntityDispatchEntryRuntimeState` | High | Runtime-state / palette-backed derived dispatch entry with owned buffers and hold-state propagation | runtime-state init/release pair, palette-entry emission families, owner-byte propagation through `g_active_dispatch_entry_farptr` | `000d:7e00 entity_dispatch_entry_init_runtime_state`; several `dispatch_entry_create_*_palette_state*` helpers build this family | `000d:8078 entity_dispatch_entry_release_runtime_state` frees owned buffers and updates hold-state propagation | inherits dispatch-entry behavior; runtime-state users dispatch through vtable slot `+0x08` after waits | owned fields `+0x41/+0x42/+0x44`, paired buffers at `+0x46/+0x48` and `+0x4a/+0x4c` | Excellent second step after the base dispatch-entry type |
| `SpriteNode` | High | Tree-based UI/render node with child links, dirty-state propagation, event dispatch, and destructor ownership | recursive tree helpers, event switch dispatch, dirty/update family, destructor | constructor not yet explicitly named in current notes, but object-init helper and repeated sprite-node ownership patterns are strong | `000b:326e sprite_node_destroy` releases child nodes and frees self | event dispatch through vtable slots `+0x14/+0x18/+0x20/+0x24`; many default vtable stubs identified in seg091 | repeated fields at `+0x19/+0x1b`, `+0x21`, `+0x23`, `+0x29`; global focus pointer interaction at `0x4fd0:0x4fd2` | Strong candidate because virtual surface is already visible and bounded |
| `Entity` | High | Base gameplay entity / actor-like object with multiple derived vtables for generic, shot, corpse, and debris behaviors | stable NE entity layout, repeated lifecycle helpers, projectile/debris subfamilies | `0007:3f2f entity_spawn`; `0007:435e shot_entity_alloc`; `0007:7490 debris_spawn`; `0007:2c92 dialog_spawn` is adjacent but likely separate family | `0007:40d4 entity_remove`; `0007:5092 entity_deactivate`; `0007:44a9 shot_entity_free` for projectile flavor | vtables `0x29aa`, `0x297e`, `0x2a1a`, `0x2a33`, `0x2a57`, plus registry vtable `0x2969`; multiple virtual-slot helper wrappers in raw notes | strong instance layout from `+0x00` through `+0xbd` in `ne-segment1.md` | Central long-term class family, but should probably be split into base + derived subfamilies |
| `DialogMenuObject` | Medium | Small UI/dialog object family sharing one vtable and event-notify wrappers | `dialog_spawn`, menu/cursor event notify wrappers, UI update callback | `0007:2c92 dialog_spawn` allocates object and stamps vtable `0x28b5` | no standalone destructor named yet in current notes | vtable `0x28b5`; `cursor_event_notify_*`, `menu_event_notify_*`, and `ui_update_callback` all behave like method wrappers | enough to establish family ownership, but layout is still thin | Good compact pilot if a smaller UI-oriented family is preferred |
| `WatchEntityController` | Medium | Global controller/watch/camera object with explicit virtual dispatch and startup/display involvement | global object at `0x2bd8`, dispatch wrapper, create-global path, startup/display callsites | `0007:ba00 watch_entity_controller_create_global` delegates to `0007:ba45 watch_entity_controller_create`, stamps type `0x2c2b`, stores global object | no direct destructor identified in current notes | repeated dispatch through vtable slots `+0x24`, `+0x2c`, and `+0x30` | global-object ownership clearer than field layout; seed row at `0x2be4` into callback table | Worth inventorying now because it will benefit immediately from namespace/method grouping |
| `EntityVmRuntime` | High | Main VM runtime object that owns owner-resource helper, cached slot/value state, and category-base setup | creation/load path is structurally stable and repeatedly cross-checked against extracted usecode evidence | `000d:44df entity_vm_runtime_init_from_path_if_configured`; `000d:4c99 entity_vm_runtime_create` | destroy path not fully named in the snippets here, but owner-resource destroy is known and runtime state/save-load consumers are well constrained | not a classic gameplay vtable family in the current notes, but method-style ownership and object fields are stable | object size and field zones strongly implied by `+0x10c/+0x10e`, `+0x117/+0x119`, `+0x1315/+0x1317` and related runtime state | Major lift target because VM readability is a blocker for recompilable source |
| `EntityVmOwnerResource` | High | File-backed helper owned by VM runtime that indexes source tables and materializes owner rows | helper object shape and per-entry loader contract are already tight | `000d:7000 entity_vm_runtime_owner_resource_create` allocates helper/object tables | paired destroy helper `000d:70fd entity_vm_runtime_owner_resource_destroy` is documented in related notes | helper method-table uses slots `+0x04` size-query and `+0x0c` materialization callback | helper-owned count `+0x14`, far-pointer table `+0x10`, paired word table `+0x18`, owner rows stride `0x0d` | One of the cleanest non-gameplay object families for typed struct work |
| `EntityVmContext` | Medium | Per-slot/per-entity VM context object built from runtime and owner-resource data | create/setup/load helpers already have clear ownership, but broader dispatch semantics are still active work | `000d:46ec entity_vm_context_create_from_slot_index` and related masked-create wrappers | no single destroy method is highlighted in the current note set used here | context-side dispatch and busy-state updates through virtual or callback-like method surface at least on the context object | stable fields include `+0x32/+0x34`, `+0xd6/+0xd8`, `+0x102`, `+0x10c/+0x10e`, `+0x11b/+0x11d`, `+0x123` | Important for VM readability, but should follow runtime and owner-resource typing |
| `CacheBackendObject` | Medium | Small backend/cache loader object with DOS file-handle state and method table | constructor and callback roles are already explicit | `0009:5600 cache_backend_object_init` allocates `0x20` bytes and seeds method-table state | no explicit destructor named in current note slice | backend callback roles at `+0x34` and `+0x0c` are verified in cache lookup/load path | concrete `0x20`-byte size; fields at `+0x08`, `+0x0c`, `+0x10`, `+0x14`, `+0x16`, `+0x18`, `+0x1c` | Good contained family for early datatype work |
| `PresentationCallbackBroker` | Low | Video/presentation-state callback broker rooted at `0x4588` | init/teardown/callback slot evidence is real, but subsystem naming remains intentionally conservative | `runtime_callback_object_init_once` family is documented, but not all constructor details are fully promoted here | `runtime_callback_object_teardown_once` and finalize path are explicit | vtable slots `+0x04`, `+0x08`, `+0x0c` all have live evidence | global state at `0x4588/0x458c/0x4590/0x4594/0x4595/0x45a6`; payload fields from caller objects at `+0x12d/+0x12f`, `+0x74f/+0x751` | Useful as a typed broker object later, but not a good first namespace/class pilot |
| `UsecodeDebuggerBreakState` | Medium | Dormant debugger-state object retained in retail binary | clear constructor and method expectations, but retail instantiation path is missing | `1408:0000 usecode_debugger_break_state_create` allocates and initializes the object | no direct destroy path highlighted in current notes | breakpoint gate callbacks through object vtable during `1408:0053` flow | internal tables and state exist, but field map is not yet summarized into one layout note | Good archival class candidate even if not a current gameplay priority |
## Recommended Modeling Order
If the goal is to make later class-authoring work fast and low-risk, the best order is:
1. `EntityDispatchEntryBase`
2. `EntityDispatchEntryRuntimeState`
3. `SpriteNode`
4. `EntityVmOwnerResource`
5. `CacheBackendObject`
6. `WatchEntityController`
7. `Entity`
8. `EntityVmRuntime`
9. `EntityVmContext`
10. `PresentationCallbackBroker`
This order prioritizes bounded families with visible constructors, derived variants, or explicit method tables before the larger gameplay and VM surfaces.
## First Pilot Candidates
### Best pilot: `EntityDispatchEntryBase`
Why it is the safest first full class lift:
- constructor variants are already named
- derived vtable variants are known
- multiple field groups have stable semantics
- destroy/release behavior is present
- it directly exercises the exact MCP features later needed: namespace creation, struct typing, method ownership, and vtable slot labeling
### Smallest bounded pilot: `CacheBackendObject`
Why it is attractive:
- explicit `0x20` size
- explicit create path
- explicit method-table callback roles
- smaller ambiguity surface than gameplay entities or the VM runtime
### Best UI-oriented pilot: `SpriteNode`
Why it is valuable:
- clear virtual event surface
- tree ownership and destructor logic already exist
- likely to benefit quickly from readable class/derived-method naming
## Per-Family Documentation Tasks
For each inventory entry, later class-upgrade work should produce the same minimum artifacts:
1. candidate namespace/class name
2. constructor and destructor list
3. instance-size estimate or known size
4. vtable root(s) and known slots
5. field map grouped by confidence
6. caller ownership notes
7. explicit `keep as free function` list for helpers that should not become methods
## Immediate Follow-Up Notes Worth Writing Later
- dedicated `EntityDispatchEntry` class-layout note with base/derived split
- dedicated `SpriteNode` virtual-slot table note
- dedicated `EntityVmRuntime` / `EntityVmOwnerResource` layout note
- dedicated `Entity` family split note covering base entity, projectile, debris, and corpse variants
## Current Rule Until MCP Catches Up
Do not rely on automatic class listings from the live MCP tools as the class-recovery source of truth. The current output is still noisy and does not reflect the actual game object families well enough for disciplined C++ lifting.
Use this inventory plus the linked evidence notes as the authoritative queue for future class-authoring work.