12 KiB
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:
EntityDispatchEntryBaseEntityDispatchEntryRuntimeStateSpriteNodeEntityVmOwnerResourceCacheBackendObjectWatchEntityControllerEntityEntityVmRuntimeEntityVmContextPresentationCallbackBroker
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
0x20size - 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:
- candidate namespace/class name
- constructor and destructor list
- instance-size estimate or known size
- vtable root(s) and known slots
- field map grouped by confidence
- caller ownership notes
- explicit
keep as free functionlist for helpers that should not become methods
Immediate Follow-Up Notes Worth Writing Later
- dedicated
EntityDispatchEntryclass-layout note with base/derived split - dedicated
SpriteNodevirtual-slot table note - dedicated
EntityVmRuntime/EntityVmOwnerResourcelayout note - dedicated
Entityfamily 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.