Files
TeslaRel410/restoration/source410/BT/MESSMGR.NOTES.md
T
CydandClaude Fable 5 8c777e1e22 BT410 5.3.115: the damage hub consolidates -- MESSMGR's three runtime bodies, a dead 1995 feature recorded, and two more donor drifts caught
SubsystemMessageManager reconstructed from the raw decomp with the wire
format pinned by the engine's own parser (TakeDamageStreamMessageHandler:
count, then type/amount/subsystemID per record -- the chain KEY carries the
damage amount, which is why AddDamageMessage keys its plugs by it).
AddDamageMessage @0049b6d8: first hit of the frame wins the common record.
ConsolidateAndSendDamage @0049b784: one DynamicMessage(0x13, 0x34) at the
hit entity, the firing weapon's explosion resource bundled per record
(binary reads roster[id]+0x3e4 blind; [T1] guarded here), DeletePlugs
teardown, commons reset. CreateWeaponExplosions @0049baa0 under its
AUTHENTIC surviving-header signature (the donor's 'SendQueuedExplosions'
rename was drift): per queued resource an Explosion::MakeMessage --
MakeMessageID 3, ExplosionClassID 0x31 (our VDATA enum ordinal matches the
binary exactly), flags 0x100, identity-rotation Origin at the impact point
-- posted to the Registry at CreationEventPriority, staggered 0.1s apart.

The 1995 archaeology: the binary computes a terrain-hit flag from a
Derivation at 0x4e6f54 (unresolved BSS class) and passes it to a parameter
THE SHIPPED BODY NEVER READS; terrainHitExplosionID is resourced by the CSS
and consumed nowhere. A declared, streamed, abandoned feature -- shipped
anyway. We pass False [T3]; behavior is byte-identical.

Ctor corrections vs our stub: weaponExplosions is UNIQUE-keyed (binary
chain ctor flag 1), the Performance registers, resource fields copy from
the stream. MechWeapon grows a public ExplosionResourceIDOf() accessor.
The 0x160-byte engine helper at +0xE0 stays staged [T3]; the CSS stays in
the authoring-family batch. No feeders call AddDamageMessage yet -- the
consolidator idles empty per frame, soak-verified live (no faults, wheel
turning).

Stubs: 13 across 10 files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 08:30:06 -05:00

3.8 KiB
Raw Blame History

MESSMGR.CPP — SubsystemMessageManager reconstruction notes

The per-mech damage/explosion hub: subsystems queue damage during a frame (AddDamageMessage), the Performance (ConsolidateAndSendDamage) folds the queue into ONE TakeDamageStreamMessage for the hit entity and flushes the bundled weapon explosions (CreateWeaponExplosions). The surviving MESSMGR.HPP (CODE/BT/BT) is authentic and untouched.

Reconstructed 2026-08-04 (5.3.115), decomp-verified (part_012.c)

  • ctor @0049bca4: weaponExplosions(NULL, True) — the binary constructs the explosion chain UNIQUE-keyed (0049bfde(.., 0, 1)); the damage chain allows duplicate keys. Installs ConsolidateAndSendDamage as the Performance (member-pointer triple @0050b6fc); copies the two streamed resource fields (res+0x30/+0x34); zeros the common record. [T3] The binary also allocates a 0x160-byte engine-internal helper at this+0xE0 (FUN_0041de1c) — not declared in the surviving header, untouched by the reconstructed paths, STAGED until identified.
  • AddDamageMessage @0049b6d8: first hit of the frame wins each common field (entity / impact point via epsilon-against-origin / zone); every message queues a DamageInformation plug KEYED BY DAMAGE AMOUNT (the chain key is read back with GetValue() at consolidation).
  • ConsolidateAndSendDamage @0049b784: wire format pinned by the ENGINE'S OWN PARSER (Entity::TakeDamageStreamMessageHandler, RP ENTITY.CPP:855): a Receiver::DynamicMessage(TakeDamageStreamMessageID == 0x13, sizeof == 0x34) with header {impactPoint@+0x1c, damageZoneIndex@+0x28, shootingEntity@+0x2c}, then << count, then << type << amount << subsystemID per record. Explosion bundling reads the FIRING weapon's resource (binary: blind roster[subsystemID]+0x3e4); [T1] guarded here (range + IsDerivedFrom(MechWeapon)) — the binary is unguarded and relies on well-formed feeders. Dispatches the stream directly at the hit entity, flushes explosions, purges with DeletePlugs() (binary FUN_00417858(,1) — the explicit teardown), resets the commons.
  • CreateWeaponExplosions @0049baa0: the authentic HEADER signature (terrain_hit, entity_hit, explode_position) — the BT411 donor's "SendQueuedExplosions" rename was port drift. Per queued resource: Explosion::MakeMessage(MakeMessageID(3), sizeof(0x5c), RegisteredClass::ExplosionClassID(0x31 — our VDATA enum ordinal matches the binary byte-for-byte), no owner, resourceID, instanceFlags 0x100, Origin{impact position, identity rotation}, entity_hit, owner mech), posted at CreationEventPriority(3) to application->GetRegistry() with delivery Now() + 0.1s × n (impacts in one frame stagger). Then purge.

The inert terrain-hit flag (recorded, not tuned)

The binary computes terrain_hit = entityHit->IsDerivedFrom(<Derivation @ 0x4e6f54>) before calling CreateWeaponExplosions. The class at 0x4e6f54 is UNRESOLVED (BSS object; no static-ctor reference survives in the decomp parts). It does not matter: @0049baa0 NEVER READS its first argument, and terrainHitExplosionID is never consumed anywhere in the shipped cluster — a declared, resourced, abandoned 1995 feature. We pass False [T3]; shipped behavior is preserved exactly. If the constant is ever resolved (candidates: a terrain/cultural class), only the dead flag changes.

Status / staging

  • CreateStreamedSubsystem @0049be10 remains a Fail stub — the authoring- side CSS family (8 fns) is batched separately; missions load prebuilt streams from BTL4.RES and never call it.
  • No feeders yet: nothing in source410 calls AddDamageMessage (the weapon damage paths still dispatch TakeDamage directly), so the consolidator runs empty every frame — verified live (5-period soak, wheel turning, no faults). When the weapon-fire damage path is rebased onto the manager, this TU is ready for it.