MP match forensics: per-peer matchlog + relay auto-upload + matchcheck

For the 8-player playtest.  Damage authority is VICTIM-side, so no single
peer sees the whole match: every -net instance now writes a compact
machine-parseable matchlog_<date>_<time>_<pid>.txt (auto-armed by -net;
BT_MATCHLOG=1/0 overrides; solo silent), and at mission end a relay-mode
pod dials the relay game port (the seat-request throwaway-dial pattern,
envelope route -9) and streams the file back -- the relay saves every
peer's copy under matchlogs/ on the operator's machine, so testers send
nothing by hand.  tools/matchcheck.py <dir> reconciles all of them:
damage claimed (FIRE/PROJ/SPLASH/RAM, shooter-side) vs applied (DMG,
victim-side authoritative), kill/death replication across observers,
PLAYER_DEAD counts, scores, version skew, replicant-application and
unattributed-damage anomalies, mid-mission disconnects.

Hooks at the authoritative sites: Mech::TakeDamageMessageHandler (DMG,
post-base, zone + post-application damageLevel), MechWeapon::
SendDamageMessage (FIRE), projectile impact/splash/collision dispatch
(PROJ/SPLASH/RAM), wreck entry (DEATH -- a ONE-SHOT latch at
MovementMode 9, NOT the transition: a replicant arrives at 9 straight
from the type-6 record header and never runs the transition branch),
BTPlayer vehicle/death/score handlers (VEHICLE/PLAYER_DEAD/SCORE), zone
crit cascade (CRIT), APP.cpp RunningMission (MISSION), L4NET host
handlers (PEER_UP/PEER_DOWN).  Every line t=/w=/st=-stamped + fflushed.

Verified 2-node: mesh run pairs A's 22 FIRE 1:1 with B's 22 DMG (same
amounts, cylinder-resolved zones, ~200ms latency); force-damage kill run
logs 103 DMG + 3 DEATH inst=M + 3 PLAYER_DEAD across three respawn
cycles victim-side and the kill SCOREs shooter-side; relay-mode run
auto-uploaded BOTH peers' files at the mission-clock stop and matchcheck
produced the full report with exactly one (correct) anomaly -- the force
hook's claim-less damage, the unattributed-damage detector working.
Relay gained a route-specific 8MB cap for the upload frame (game frames
stay capped at 1600).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-22 13:22:10 -05:00
co-authored by Claude Opus 4.8
parent 3097d269b4
commit 753540de96
17 changed files with 947 additions and 2 deletions
+10
View File
@@ -1486,6 +1486,11 @@ void
#endif
Tell("Application::RunMissionMessageHandler - running mission\n");
{ // MP match forensics (game-side matchlog.cpp; single-exe link)
extern int BTMatchLogActive();
extern void BTMatchLog(const char *, const char *, ...);
if (BTMatchLogActive()) BTMatchLog("MISSION", "run");
}
applicationState.SetState(RunningMission);
gameStarted = Now();
break;
@@ -1613,6 +1618,11 @@ void
case ResumingMission:
Tell("Application::ResumeMissionMessageHandler - Running mission\n");
{ // MP match forensics (game-side matchlog.cpp; single-exe link)
extern int BTMatchLogActive();
extern void BTMatchLog(const char *, const char *, ...);
if (BTMatchLogActive()) BTMatchLog("MISSION", "run");
}
applicationState.SetState(RunningMission);
gameStarted = Now();
break;