Files
BT411/scratchpad/night6/bench_common.sh
T
Joe DiPrimaandClaude Fable 5 9c83a468db #82 ROOT FIX: reconstruct the crash SELF-DAMAGE -- wall-grinding now hurts,
the knockdown storm self-limits, peers keep the limp

The 'peers see a limping mech skating' report decomposed into a wall-grind
KNOCKDOWN STORM: a gimped mech held against a blocking solid re-crashes each
time its gg cycle rebuilds speed (the gg ceiling is authentically the clip's
natural speed -- bhk1 ~14.9 u/s, ceiling+divisor @0x544/0x548, loader formula
byte-matched -- so iv2 ~222 >> the 40.0 threshold @0x4ab184), and every
type-5 KNOCKDOWN broadcast floors all peers' replicants into knockdown/trn
churn: gliding + leg-lifts = skating.  Turning and crushable cars were
A/B-exonerated (grass circling: 198 replicant gimp entries, 17 crunches,
zero broadcasts).

What the binary has that the port lacked -- recovered from the EXPORT GAP by
raw disasm (scratchpad/night6/gap_4a9770.txt, @4aa89f-4aaab4) -- is the crash
branch's tail: fallDirection = worldToLocal(damageForce) (FUN_0040879c, M^T v,
un-normalized), fallScalar = -(fallDirection . localVelocity.linearMotion),
and a self-dispatched TakeDamageMessage{0x64, zone=-1, the engine-computed
collision Damage verbatim}.  A wall crash COSTS ARMOR, so the grind degrades
the mech instead of looping forever.  That dispatch was the long-standing
'DEFERRED' note in the response policy; now reconstructed.

Falsified en route (comments + KB corrected, do not revive): the stagger's
FUN_004a4c54(1)/(0x20) 'action-request flags' feed NO drive suppressor --
image-wide sweep + full gap disasm show word[this+0x18] is read only by the
net record emitter; the bmp clip applies NO root motion (adv=0 measured); the
'gimp cap 5.8' figure was the BACK-cycle stride printed under a misleading
label (now ggCapL/R; @0x52c has no binary consumer).

Verified (mp_gimpAB rigs): arena1 wall-grind now 4 bounded strikes, limper
dies of its crashes and respawns cleanly twice (START->RESET, no strand);
grass circling unchanged-clean (198 replicant gimp states, 0 knocks).
Rig: pid capture race fixed (a missed winpid left a stale node holding the
-net port -> null runs), per-config sweep added.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 16:18:28 -05:00

92 lines
4.4 KiB
Bash

#!/usr/bin/env bash
# ===========================================================================
# BENCH COMMON -- launch a local test node EXACTLY as a field player's
# shortcut does, so what we see locally is what they see.
#
# WHY THIS FILE EXISTS (2026-07-30): local benches had drifted from the
# shipped launchers, and every divergence cost a debugging session:
# * no BT_START_INSIDE -> benches opened in the EXTERNAL CHASE camera while
# every player starts in the COCKPIT. Hours were
# spent on a "broken HUD" that was simply the first
# first-person look at a view the benches never showed.
# * novice bench eggs -> every SHIPPED egg is `expert`; novice silences the
# whole heat model, crits and jams, so bench combat
# was not the combat players get.
# * 1-logical-processor affinity pins -> starved the gauge executive and
# produced a false "the comms panel never counts"
# reading. Two LPs per node keeps MP jitter pinned
# (the documented single-box fix) without starving.
#
# THE PLAYER ENV IS THE CONTRACT. It is copied verbatim from the shipped
# play_solo.bat / join.bat (dist zip). bt_assert_player_env compares this
# list against a shipped .bat when one is available, so drift is caught.
# ===========================================================================
BT_ROOT=/c/git/bt411
BT_EXE=$BT_ROOT/build/Release/btl4.exe
# PIDs THIS run launched. A blanket `taskkill /IM btl4.exe` at teardown kills
# every game on the machine -- including a NEWER bench a previous wrapper's
# sleep outlived. That silently shot down two live sessions, so each run now
# tracks and kills only its own children.
BT_PIDFILE=/tmp/bt_bench_pids.$$
# --- the exact env every shipped launcher sets -----------------------------
bt_player_env () {
export BT_PLATFORM=glass # unified build, desktop cockpit layer
export BT_START_INSIDE=1 # COCKPIT eyepoint -- what a player sees
export BT_DEV_GAUGES=1 # MFD/gauge surfaces + cockpit surround
}
# --- warn if the shipped launcher has gained/lost a setting ----------------
bt_assert_player_env () {
local bat="$BT_ROOT/dist/BT411_4.11.643/play_solo.bat"
[ -f "$bat" ] || return 0
for v in BT_PLATFORM BT_START_INSIDE BT_DEV_GAUGES; do
grep -qi "set $v=" "$bat" || echo "[bench] WARNING: shipped bat no longer sets $v"
done
}
# --- launch one node -------------------------------------------------------
# bt_launch <logfile> <egg> <affinity> [extra args...] (env: extra BT_* vars)
# Two logical processors per node: disjoint core sets keep single-box packet
# delivery even (peer-shakiness fix) without starving the gauge executive.
bt_launch () {
local log="$1" egg="$2" aff="$3"; shift 3
( bt_player_env
export BT_LOG="$log" BT_AFFINITY="$aff"
"$BT_EXE" -egg "$egg" "$@" &
# the winpid pseudo-file races process start -- poll briefly; a missed pid
# here left a stale node holding the -net port and null-ran the next config
for _i in 1 2 3 4 5; do
[ -f /proc/$!/winpid ] && { cat /proc/$!/winpid >> "$BT_PIDFILE"; break; }
sleep 0.3
done )
}
# --- an EXPERT copy of an egg (what players actually fly) ------------------
# Shipped eggs are all experience=expert. Bench eggs must match unless the
# harness itself needs otherwise (see bt_novice_egg).
bt_expert_egg () { # bt_expert_egg <src.egg> <dst.egg>
sed 's/^experience=.*/experience=expert/' "$1" > "$2"
}
# --- a NOVICE copy, for the harnesses that genuinely require it ------------
# ONLY the aimed-leg gimp bench: on expert the self-damage bursts roll CRITS on
# the aimed leg, and one myomers crit leaves the mech turning-but-not-moving --
# which destroys the limp demo. Novice gates crits; the leg gimp still fires.
# Any bench using this is NOT showing player-authentic damage behaviour.
bt_novice_egg () { # bt_novice_egg <src.egg> <dst.egg>
sed 's/^experience=.*/experience=novice/' "$1" > "$2"
echo "[bench] NOTE: novice egg $2 -- crits/heat/jams are GATED OFF (harness requirement)"
}
# --- kill ONLY the nodes this run started --------------------------------
bt_kill_ours () {
[ -f "$BT_PIDFILE" ] || return 0
while read -r pid; do
[ -n "$pid" ] && taskkill //F //PID "$pid" > /dev/null 2>&1
done < "$BT_PIDFILE"
rm -f "$BT_PIDFILE"
}