#!/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 [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 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 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" }