bench: two-node CROSS-POD damage verification for the #95 burst change
Projectile damage now Dispatches directly at the victim instead of going through
the shooter's SubsystemMessageManager, so cross-pod delivery had to be proven on
real nodes rather than assumed.
RESULT: cross-pod delivery intact, and the cluster count survives the wire.
Node A fired 38 missile rounds with bursts {1:5,2:6,3:6,4:7,5:7,6:7}; node B
received exactly the matching zone applications {2:12,3:18,4:28,5:35,6:42} --
i.e. rounds x burst, per burst band, exact. 135 of B's 142 explosive
applications carried burst > 1 (the manager path used to drop it to 1).
Energy stayed at burst 1 on both nodes; no crash on either.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c23d06cbb5
commit
3a22c334ac
@@ -0,0 +1,41 @@
|
||||
"""Cross-pod damage analysis for the #95 cluster-burst change.
|
||||
|
||||
For each node: what it FIRED (shooter-side projectile impacts) versus what it
|
||||
RECEIVED (zone applications), so a round fired on one node can be seen landing
|
||||
on the other with its burst count intact.
|
||||
"""
|
||||
import re, sys, collections
|
||||
|
||||
def load(path):
|
||||
return open(path, encoding="latin-1", errors="replace").read()
|
||||
|
||||
RX_HIT = re.compile(r"\[dmghit\] mech=(\S+) zone=(\d+) vital=(\d) type=(\d+) "
|
||||
r"amt=([0-9.eE+-]+) burst=([0-9.]+) lvl ([0-9.eE+-]+)->([0-9.eE+-]+)")
|
||||
RX_IMP = re.compile(r"\[projectile\] IMPACT damage=([0-9.]+) subsys=(\d+).*?burst=(\d+)")
|
||||
|
||||
for name, path in [("NODE A (1501)", sys.argv[1]), ("NODE B (1601)", sys.argv[2])]:
|
||||
d = load(path)
|
||||
imps = RX_IMP.findall(d)
|
||||
hits = RX_HIT.findall(d)
|
||||
print("=" * 62)
|
||||
print("%s %s" % (name, path))
|
||||
print(" FIRED : %d projectile impacts, bursts=%s"
|
||||
% (len(imps), dict(sorted(collections.Counter(int(b) for _, _, b in imps).items()))))
|
||||
byType = collections.defaultdict(list)
|
||||
for mech, zone, vital, ty, amt, burst, a, b in hits:
|
||||
byType[int(ty)].append((float(amt), int(float(burst)), float(b) - float(a)))
|
||||
print(" TOOK : %d zone applications" % len(hits))
|
||||
for ty in sorted(byType):
|
||||
v = byType[ty]
|
||||
label = {2: "EXPLOSIVE(missile/AC)", 3: "ENERGY(beam)", 0: "COLLISION"}.get(ty, "type%d" % ty)
|
||||
print(" %-22s %3d apps bursts=%-28s dlvl=%.4f"
|
||||
% (label, len(v),
|
||||
dict(sorted(collections.Counter(b for _, b, _ in v).items())),
|
||||
sum(x[2] for x in v)))
|
||||
mult = [b for _, b, _ in byType.get(2, []) if b > 1]
|
||||
print(" >>> multi-burst EXPLOSIVE applications received: %d %s"
|
||||
% (len(mult), "<-- cluster count SURVIVED the wire" if mult else "<-- NONE (burst lost!)"))
|
||||
for tag in ("Unhandled", "assert", "ACCESS_VIOLATION"):
|
||||
n = len(re.findall(tag, d, re.I))
|
||||
if n:
|
||||
print(" !! %s x%d" % (tag, n))
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
# CROSS-POD damage verification for the #95 cluster-burst change.
|
||||
#
|
||||
# WHY: projectile damage no longer goes through the shooter's
|
||||
# SubsystemMessageManager -- it now Dispatches DIRECTLY at the struck entity, as
|
||||
# the binary's Missile does (FUN_004be078). Dispatch is documented to reroute
|
||||
# cross-pod for a REPLICANT victim on its own, but the manager routing that used
|
||||
# to carry it is gone, so this must be proven on two real nodes rather than
|
||||
# assumed.
|
||||
#
|
||||
# Two pilots chase each other and fire in throttled bursts (unthrottled spam
|
||||
# trips the FailureHeat all-weapons brick and combat dies).
|
||||
#
|
||||
# PASS, read on the VICTIM's log (the node that did NOT fire the round):
|
||||
# * [dmghit] type=2 rows appear at all -> cross-pod damage arrives
|
||||
# * those rows carry burst > 1 -> the cluster count SURVIVED
|
||||
# the wire (this is the whole
|
||||
# point: the manager used to
|
||||
# drop it)
|
||||
# * their damageLevel actually climbs -> armour is really applied
|
||||
# Plus: no crash, and matchlog PROJ rows on the shooter pair with DMG on victim.
|
||||
set -x
|
||||
. /c/git/bt411/scratchpad/night6/bench_common.sh
|
||||
cd /c/git/bt411/content || exit 1
|
||||
bt_assert_player_env
|
||||
rm -f mpb_a.log mpb_b.log
|
||||
bt_expert_egg MP.EGG MPB.EGG
|
||||
|
||||
launch () { # $1=log $2=affinity $3=port
|
||||
BT_MP_LOG=1 BT_DMG_LOG=1 BT_MATCHLOG=1 BT_PROJ_LOG=1 BT_DEATH_LOG=1 \
|
||||
BT_GOTO=enemy BT_GOTO_STOP=120 BT_AUTOFIRE=1 BT_AF_MISSILE=1 BT_AF_PERIOD=6 \
|
||||
bt_launch "$1" MPB.EGG "$2" -net "$3"
|
||||
sleep 2
|
||||
}
|
||||
|
||||
launch mpb_b.log 0x0C 1601
|
||||
launch mpb_a.log 0x03 1501
|
||||
sleep 5
|
||||
python ../tools/btconsole.py MPB.EGG 127.0.0.1:1501 127.0.0.1:1601 &
|
||||
PC=$!
|
||||
|
||||
sleep 240
|
||||
kill $PC 2>/dev/null
|
||||
bt_kill_ours
|
||||
rm -f MPB.EGG
|
||||
echo "=== DONE -- analyse with mp_burst.py ==="
|
||||
Reference in New Issue
Block a user