Crusader_Decomp/docs/entity-class-family-split.md

170 lines
5.6 KiB
Markdown
Raw Normal View History

2026-04-05 18:27:09 +02:00
# Entity Class Family Split
## Purpose
This note breaks the large seg001 `Entity` lane into a conservative class-family model that can later be promoted in Ghidra or emitted as C++ without pretending that every vtable and helper belongs to one monolithic base class.
Current goal is not full inheritance recovery. Current goal is to identify the safest boundaries between:
- one shared gameplay-entity core layout
- projectile-specific allocation and movement behavior
- debris/corpse variants
- registry/helper surfaces that look adjacent but should not be merged automatically
## Core Shared Entity Object
Strongest current common object is the gameplay entity body documented in [docs/ne-segment1.md](docs/ne-segment1.md).
Stable shared anchors:
- `0007:3f2f entity_spawn`
- `0007:40d4 entity_remove`
- `0007:4552 entity_set_position`
- `0007:4591 entity_try_place`
- `0007:5092 entity_deactivate`
Stable shared fields from the current note set include:
- `+0x00` vtable pointer
- `+0x02` slot index
- `+0x04` entity type
- `+0x19/+0x1a` flags
- `+0x3c` sprite handle
- `+0x45/+0x47/+0x49` world position
- `+0x4f/+0x51/+0x53` base position
- `+0x54/+0x56/+0x58` previous position
This is the safest current candidate for a future `Entity` or `ActorBase` style root.
## Candidate Split
### 1. `Entity` base gameplay family
Best current scope:
- allocation/spawn and placement
- common position, flags, facing, and sprite ownership
- generic remove/deactivate behavior
- registry-facing slot identity
Best current vtable anchor:
- generic/AI entity vtable `0x29aa`
Current caution:
- this family likely includes several behaviorally different actors, but the verified note set still supports one shared base before the split gets more specific.
### 2. `ShotEntity` or projectile-derived family
Strong anchors:
- `0007:28ce shot_entity_alloc`
- `0007:44a9 shot_entity_free`
- `0007:4659 projectile_init_vector`
- `0007:4b78 projectile_check_hit`
- `0007:4c2e projectile_step_update`
- `0007:4d28 projectile_trace_ray`
- `0007:51ad projectile_update_tick`
- `0007:5a99 projectile_apply_hit`
Best current distinct evidence:
- dedicated vtable `0x297e`
- extra projectile ownership/target fields through `+0x6a..+0xbd`
- separate shot sprite handle at `+0x3f`
- dedicated cleanup path in `shot_entity_free`
Current safest interpretation:
- projectile objects are not just one mode of the generic entity vtable; they deserve at least one derived-family model with their own ctor/free/update surface.
### 3. `DebrisEntity` family
Strong anchors:
- `0007:7490 debris_spawn`
- `0007:75ff entity_die`
Best current distinct evidence:
- dedicated debris/fragment vtable `0x2a57`
- corpse/debris-adjacent vtable pair `0x2a1a` and `0x2a33`
- death-spawn path uses separate velocity/facing behavior rather than only the generic entity update lane
Current safest interpretation:
- debris should stay separate from `ShotEntity`; both share movement-style fields but not the same lifecycle intent.
### 4. `CorpseEntity` or actor-remnant family
Strong current evidence:
- vtable pair `0x2a1a` and `0x2a33`
- adjacency to `entity_die` and debris-spawn behavior
Current caution:
- the notes support a corpse/remnant family, but not yet a crisp split between static remains, actor corpse, and debris fragments.
- keep this as a provisional derived branch until a dedicated caller pass closes object lifetime more tightly.
### 5. Adjacent but probably separate: dialog/menu object lane
Anchor:
- `0007:2c92 dialog_spawn`
Why it should stay separate:
- vtable `0x28b5`
- callback registration at `0x39ca`
- behavior is UI/dialog-style rather than ordinary gameplay entity movement or projectile logic
Current safest interpretation:
- this object is near the entity notes because it lives in the same broad segment lane, but it should not be promoted under the core gameplay `Entity` family automatically.
## Registry And Helper Surfaces That Should Not Be Mis-modeled
### Entity registry vtable `0x2969`
Current evidence in [docs/ne-segment1.md](docs/ne-segment1.md) shows `0x2969` stored at `0x39ca + slot*4` as a registry vtable rather than as the entity instance's primary vtable.
That means:
- do not treat `0x2969` as a normal `Entity` virtual table
- keep registry or handle-table behavior separate from per-instance inheritance
### Pure helpers that should remain free functions for now
Examples:
- `snap_entity_to_ground`
- `spawn_entity_checked`
- `map_find_spawn_point`
- `actor_find_in_view`
These may operate on entities or produce entities, but current evidence still reads better as subsystem helpers than as obvious instance methods.
## Recommended Promotion Order
1. model the shared `Entity` base layout first
2. split `ShotEntity` next because its ctor/free/update lane is strongest
3. split debris/corpse branches only after one more caller-side lifetime pass
4. leave dialog/menu object modeling separate from the entity inheritance tree
## Source-Emission Guidance
If this family is emitted to provisional C++ later, safest first skeleton is:
- one `Entity` base struct/class with the stable common layout
- one `ShotEntity` derived placeholder
- one `DebrisEntity` derived placeholder
- one unresolved `CorpseLikeEntity` placeholder if needed
- separate `DialogMenuObject` class rather than folding it into the gameplay entity tree
## Bottom Line
The current evidence strongly supports a shared gameplay entity core, but it does not support flattening generic actor, projectile, debris, corpse, and dialog/menu behavior into one class.
The right near-term move is `base first, derived families second, adjacent objects separate`.