MP task #47 SOLVED: cross-pod damage + kill (validate the master mech)

Full cross-pod KILL now works: instance A (host 2) shoots B's mech (host 3)
dead over the network; B runs the death transition on its own screen. Verified
on a 2-node one-box run (BT_MP_FORCE_DMG on A): B's mech takes ~36 remote hits
of 12 and is DESTROYED, with wreck swap + explosion.

ROOT CAUSE (one bug): B's own MASTER mech was INVALID. Entity::Receive(Event*)
does `if(!IsValid()) event->Defer()` -- so a cross-pod-delivered TakeDamage that
arrived, resolved to B's real mech, and Posted, was DEFERRED forever; the handler
never ran. The reconstructed Mech::Make force-set ValidFlag only for replicants
(the P6 bring-up hack for the partial MakeReady handshake); a locally-created
master never got validated.

FIX (one line): Mech::Make now sets ValidFlag for the master too -- the
reconstructed ctor builds the mech synchronously, so it's safe. Nothing else
changed: targeting, the virtual victim->Dispatch, the replicant reroute, the
wire, receive, and id resolution were ALL already correct.

Two prior root causes were BOTH mis-diagnoses from the WRONG messageID:
Entity::TakeDamageMessageID is 18, not 21. Every earlier probe filtered
msgID==21, never matched a real TakeDamage, and mis-correlated the stray 21
hits' 3:19 / classID-48 against the real 3:22 hit -- inventing (a) a "cross-TU
Entity layout divergence" (disproven: offsetof identical in both TUs, sizeof
444, entityID@0x17C) and (b) a "localID corrupted on the wire". Both FALSE; the
id is correct end-to-end (3:22 = B's master).

- game/reconstructed/mech.cpp: validate master + replicant at Make.
- game/reconstructed/mech4.cpp: BT_MP_FORCE_DMG cleaned to a concise gated
  2-node cross-pod reproducer (real virtual Dispatch path).
- context/multiplayer.md, reconstruction-gotchas.md: corrected root cause +
  the validity-defers-cross-pod gotcha. Engine diagnostics reverted to clean.

Solo un-regressed (the solo enemy was already force-valid; the change only ADDS
ValidFlag). btl4.exe builds; full mission loop clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-09 12:52:26 -05:00
co-authored by Claude Fable 5
parent 04a2049ce2
commit 54b6663b4d
4 changed files with 75 additions and 66 deletions
+11 -8
View File
@@ -689,14 +689,17 @@ Mech*
return 0;
}
new (mech) Mech(creation_message, DefaultData); // FUN_004a1674
// P6 bring-up (multiplayer): a REPLICANT never gets the master's MakeReady/
// CheckLoad validity handshake (the engine's interest layer is a partial
// implementation), and an INVALID entity defers every message as an event
// (ENTITY.cpp Receive/Dispatch) -- so its network UPDATES never apply AND the
// deferred-event churn keeps the peer's CreatingMission queue from ever going
// quiet. Validate replicants at creation (same fix the spawned test dummy
// needed); the authentic MakeReady flow is future work.
if (mech->GetInstance() == Entity::ReplicantInstance)
// P6 bring-up (multiplayer): the port's MakeReady/CheckLoad validity handshake
// is a partial implementation, so a mech is never authentically validated. An
// INVALID entity DEFERS every dispatched message forever (ENTITY.cpp
// Entity::Receive -> event->Defer), which silently drops cross-pod TakeDamage
// at the owning MASTER (task #47: B receives + resolves the hit to its own mech,
// classID 3001, but Entity::Receive sees valid=0 and defers it). It also stalls
// a REPLICANT's network UPDATES and churns the peer's CreatingMission queue. The
// reconstructed ctor builds the whole mech synchronously, so validating here is
// safe for BOTH instances (a master must be valid to take cross-pod damage; a
// replicant to apply updates). The authentic MakeReady flow is future work.
if (mech != 0)
{
mech->SetValidFlag();
}