The operator's 'many seconds between display updates', run to ground: MECHANISM (verified in source AND the shipped exe bytes): main passes GetTicksPerSecond() as ApplicationManager's frame RATE, so frameDuration is microscopic and RunMissions runs flat-out -- exactly ONE background slot per loop frame, shipped and ours alike (ctor constant @0044f2d8 == 1.0f, read straight out of BTL4OPT.EXE). That slot feeds a 7-task ring; the gauge renderer gets 1/7th of slots, one ACTIVE gauge per slot, and the screen blits once per completed wheel pass. The wheel is 136 gauges -- and the BT_GAUGE_LOG roster dump shows all 136 are real cockpit instruments (26 armor colormappers, leak gauges, cooling loops, weapon clusters...): a Tesla pod shows everything at once, so the roster is AUTHENTIC and must not be trimmed. Per-instrument latency is therefore 7 x 146 / loop_fps -- the loop rate is the only lever. THE DEFECT: build410.sh compiled -O2 alone. The authentic release tier (CODE/BT/OPT.MAK) is -O2 -Ot -Oc -Og -O -Ol -Z -Ob -Oe -Oi -Om -Op -Ov. Adopting it (all 234 TUs clean, no BC4.52 optimizer ICEs) doubled the loop: 16.7 -> ~30 fps wall on the rig. Shipped fifo throughput is still ~2x ours (11.8KB/s vs 6.4KB/s, governor-conflated) -- residual gap is an open question pinned in GAUGE-CADENCE-NOTES.md with the operator A/B ask. Instrumentation kept, cheap and gated: slot/wheel counters on the [stack] line (BT_STACK_LOG), one-shot roster dump (BT_GAUGE_LOG), tick-delta timers compile-gated BT_TICK_PROBES (OFF -- guest tick sums proved to be trap-burst artifacts in the emulator, not costs; wall rates are the only trustworthy measure). New: MUNGA/APPTASK.CPP shadow, fifofps.py (true board fps from a fifodump), pod_render_bgprobe.conf. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
203 lines
11 KiB
Bash
203 lines
11 KiB
Bash
#!/bin/bash
|
|
# build410.sh -- assemble BTL4OPT.EXE from the reconstructed 4.10 tree.
|
|
#
|
|
# Stages:
|
|
# 1. mass-compile the merged engine source (CODE/BT over CODE/RP over
|
|
# source410 backfills) into build410/obj/{munga,mungal4}/
|
|
# 2. compile the BT game TUs (CODE originals + source410) into
|
|
# build410/obj/{bt,btl4}/
|
|
# 3. tlib the four libs; prebuilt-1995 .obj fallbacks fill source gaps
|
|
# 4. tlink32 with the authentic OPT.MAK order; unresolved externals ->
|
|
# build410/UNRESOLVED.txt (the canonical remaining-work ledger)
|
|
#
|
|
# Usage: ./build410.sh [engine|bt|libs|link|all|status]
|
|
|
|
T=/c/VWE/TeslaRel410
|
|
TW=c:/VWE/TeslaRel410
|
|
export PATH="$T/BORLAND/BC45/BIN:$PATH"
|
|
C=$TW/CODE/BT
|
|
R=$TW/CODE/RP
|
|
S=$TW/restoration/source410
|
|
B=$T/restoration/build410
|
|
Bw=$TW/restoration/build410
|
|
|
|
INC="$S/override;$C/BT_L4;$C/BT;$C/MUNGA;$C/MUNGA_L4;$C/MUNGA_L4/SOS/BC4;$S/MUNGA;$S/MUNGA_L4;$R/MUNGA;$R/MUNGA_L4;$R/MUNGA_L4/NetNub;$R/MUNGA_L4/sos/bc4;$C/MUNGA_L4/LIBDPL;$C/MUNGA_L4/NETNUB;$C/MUNGA_L4/NETNUB/INCLUDE;$S/MUNGA_L4;$R/MUNGA_L4/libDPL;$R/MUNGA_L4/libDPL/dpl;$S/shim;$S/BT;$S/BT_L4;$TW/BORLAND/BC45/INCLUDE"
|
|
# Optimizer set = CODE/BT/OPT.MAK verbatim (the shipped release tier). -O2
|
|
# alone leaves the global optimizer half off; the missing switches (global
|
|
# CSE/regalloc, invariant motion, copy propagation, inline intrinsics,
|
|
# redundant-load suppression, loop opts) measured ~3x wall speed on the rig
|
|
# (shipped 11.8KB/s fifo vs 4.1KB/s ours, 2026-08-04) and starved the gauge
|
|
# wheel to one background slot per frame ("many seconds between updates").
|
|
FLAGS="-c -DLBE4 -DDEBUG_LEVEL=0 -DDEBUG_STREAM=cout \
|
|
-b -r -ff -AT -k- -N- -v- -5 -a4 -V -Jg -x- -RT- \
|
|
-O2 -Ot -Oc -Og -O -Ol -Z -Ob -Oe -Oi -Om -Op -Ov -w-"
|
|
|
|
mkdir -p "$B"/obj/{munga,mungal4,bt,btl4} "$B"/lib
|
|
|
|
# Header-dependency stamps: cc() has no per-TU include tracking, so a header
|
|
# edit must invalidate every obj that could embed its layout (a stale obj with
|
|
# an old struct layout SILENTLY corrupts adjacent members at runtime -- the
|
|
# 2026-07-21 MechWeapon::rearFiring stomp). CODE/ is the immutable archive;
|
|
# only source410/ headers change. Engine-level headers (MUNGA/shim/override)
|
|
# are included by everything; game headers (BT/BT_L4) only by the game buckets.
|
|
hstamp() { # hstamp <dir...> -> newest header mtime (epoch secs, 0 if none)
|
|
local t
|
|
t=$(find "$@" -maxdepth 1 \( -iname '*.hpp' -o -iname '*.h' \) -printf '%T@\n' 2>/dev/null \
|
|
| sort -n | tail -1)
|
|
echo "${t%%.*}"
|
|
}
|
|
HS_ENGINE=$(hstamp "$S/MUNGA" "$S/MUNGA_L4" "$S/shim" "$S/override")
|
|
HS_GAME=$(hstamp "$S/BT" "$S/BT_L4")
|
|
[ -z "$HS_ENGINE" ] && HS_ENGINE=0
|
|
[ -z "$HS_GAME" ] && HS_GAME=0
|
|
|
|
# compile one TU into a bucket; skip only if the obj is newer than the source
|
|
# AND the relevant header stamps
|
|
cc() { # cc <bucket> <src>
|
|
local out="$B/obj/$1/$(basename "${2%.*}" | tr 'A-Z' 'a-z').obj"
|
|
if [ -f "$out" ] && [ "$out" -nt "$2" ]; then
|
|
local omt=$(stat -c %Y "$out")
|
|
local need=$HS_ENGINE
|
|
case "$1" in bt|btl4) [ "$HS_GAME" -gt "$need" ] && need=$HS_GAME;; esac
|
|
[ "$omt" -ge "$need" ] && return 0
|
|
fi
|
|
if bcc32 $FLAGS -I"$INC" -o"$(cygpath -w "$out" 2>/dev/null || echo $out)" "$2" \
|
|
> "$B/obj/$1/$(basename "${2%.*}").log" 2>&1; then
|
|
return 0
|
|
else
|
|
rm -f "$out"; return 1
|
|
fi
|
|
}
|
|
|
|
# merged engine source view: BT tree wins, RP fills, source410 backfills last
|
|
merged() { # merged <BTdir> <RPdir> [S410dir]
|
|
{ ls "$1"/*.CPP "$1"/*.cpp 2>/dev/null | sed 's/.*[\\/]//'
|
|
ls "$2"/*.CPP "$2"/*.cpp 2>/dev/null | sed 's/.*[\\/]//'
|
|
[ -n "$3" ] && ls "$3"/*.CPP 2>/dev/null | sed 's/.*[\\/]//'
|
|
} | tr 'A-Z' 'a-z' | sort -u
|
|
}
|
|
srcfor() { # srcfor <name.cpp> <BTdir> <RPdir> [S410dir]
|
|
case "$1" in
|
|
filestrm.cpp) echo "$3/FILESTRM.CPP"; return;; # BT pair = post-4.10 drift
|
|
l4vidper.cpp|l4tsdpl.cpp) return;; # not in mungal4.lib
|
|
filestub.cpp) return;; # stub.lib member (prebuilt obj)
|
|
esac
|
|
for d in "$4" "$2" "$3"; do # source410 overrides, then BT, then RP
|
|
[ -z "$d" ] && continue
|
|
for f in "$d"/*.CPP "$d"/*.cpp; do
|
|
[ -f "$f" ] || continue
|
|
[ "$(basename "$f" | tr 'A-Z' 'a-z')" = "$1" ] && { echo "$f"; return; }
|
|
done
|
|
done
|
|
}
|
|
|
|
stage_engine() {
|
|
local ok=0 fail=0 failed=""
|
|
for lib in munga mungal4; do
|
|
local bd rd sd
|
|
if [ $lib = munga ]; then bd=$C/MUNGA; rd=$R/MUNGA; sd=$S/MUNGA; else bd=$C/MUNGA_L4; rd=$R/MUNGA_L4; sd=$S/MUNGA_L4; fi
|
|
for n in $(merged "$bd" "$rd" "$sd"); do
|
|
src=$(srcfor "$n" "$bd" "$rd" "$sd")
|
|
[ -z "$src" ] && continue
|
|
if cc $lib "$src"; then ok=$((ok+1)); else fail=$((fail+1)); failed="$failed $lib/$n"; fi
|
|
done
|
|
done
|
|
echo "ENGINE: $ok ok, $fail fail"
|
|
for f in $failed; do echo " FAIL $f"; done | head -60
|
|
for f in $failed; do echo "$f"; done > "$B/ENGINE-FAILURES.txt"
|
|
}
|
|
|
|
stage_bt() {
|
|
local ok=0 fail=0
|
|
for n in $(merged "$C/BT" /dev/null "$S/BT"); do
|
|
src=$(srcfor "$n" "$C/BT" /dev/null "$S/BT")
|
|
[ -z "$src" ] && continue
|
|
if cc bt "$src"; then ok=$((ok+1)); else fail=$((fail+1)); echo " FAIL bt/$n"; fi
|
|
done
|
|
for n in $(merged "$C/BT_L4" /dev/null "$S/BT_L4"); do
|
|
src=$(srcfor "$n" "$C/BT_L4" /dev/null "$S/BT_L4")
|
|
[ -z "$src" ] && continue
|
|
if cc btl4 "$src"; then ok=$((ok+1)); else fail=$((fail+1)); echo " FAIL btl4/$n"; fi
|
|
done
|
|
echo "BT: $ok ok, $fail fail"
|
|
}
|
|
|
|
# Authentic 1995 lib member ORDER (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK).
|
|
# Order is LOAD-BEARING: tlink emits static-init records in module pull order,
|
|
# and base-class statics (e.g. NetworkClient::ClassDerivations, network.obj)
|
|
# must construct before derived ones (IcomManager, icom.obj). Alphabetical
|
|
# order boots into a null-vptr crash in Derivation::Derivation.
|
|
ORDER_munga="heap cstr memblock memreg memstrm filestrm verify namelist notation fileutil color resource scalar rect2d random angle vector3d vector4d point3d unitvec rotation motion origin affnmtrx linmtrx matrix mtrxstk spline ray line sphere normal plane extntbox bndgbox boxtree boxlist boxsolid boxsort boxsphr boxcone boxramp boxiramp boxwedge boxdisks boxtile time vdata iterator link plug objstrm socket node slot chain sfeskt srtskt schain vchain tree table hash trace receiver event evtstat cmpnnt simulate subsystm joint network damage entity entityid nttmgr entity2 envirnmt mover segment jmover watcher host hostmgr console scnrole team exptbl caminst cammgr camship cammppr eyecandy player director dropzone explode terrain cultural doorfram door registry lattice intorgn collorgn interest collasst update reticle rndorgn renderer vidrend audio audent audtime audwgt audlvl audloc audcmp audsrc audmidi audseq audwthr audrend wrhous gaugmap gauge lamp gaugrend gaugalrm graph2d mode controls mission apptask app appmgr appmsg spooler icom maptool modtool animtool audtools tool"
|
|
ORDER_mungal4="l4trace l4file l4time netshare l4serial l4svga16 joystick pcspak l4host l4net l4dplmem l4vidrnd l4video startdpl sosmawe l4audhdw l4audio l4audlvl l4audwtr l4audres l4audrnd l4wrhous l4vb8 l4vb16 l4gauima l4grend l4gauge l4lamp l4plasma l4ctrl l4keybd l4mouse l4rio l4mppr l4app l4splr l4icom l4vidtul l4audtul l4gautul l4ctltul"
|
|
ORDER_bt="btmssn messmgr mechdmg dmgtable mech mech2 mech3 mech4 mechsub mechtech heat mechmppr powersub sensor gnrator gyro torso hud myomers mechweap emitter ppc projweap mislanch ammobin gauss projtile misthrst seeker missile btplayer btteam btdirect btreg btcnsl bttool"
|
|
ORDER_btl4="btl4mode btl4rdr btl4gaug btl4gau2 btl4gau3 btl4grnd btl4galm btl4vid btl4mppr btl4arnd btl4mssn btl4app btl4pb"
|
|
|
|
stage_libs() {
|
|
cd "$B/lib"
|
|
for lib in munga mungal4 bt btl4; do
|
|
rm -f $lib.lib
|
|
ls "$B/obj/$lib"/*.obj >/dev/null 2>&1 || continue
|
|
: > $lib.rsp
|
|
eval "order=\$ORDER_$lib"
|
|
added=" "
|
|
# authentic makefile order first: compiled obj, else prebuilt-1995 obj
|
|
for n in $order; do
|
|
if [ -f "$B/obj/$lib/$n.obj" ]; then
|
|
printf '+..\obj\%s\%s.obj &
|
|
' "$lib" "$n" >> $lib.rsp
|
|
added="$added$n "
|
|
else
|
|
pre=$(find $R/MUNGA/opt $R/MUNGA_L4 -iname "$n.obj" 2>/dev/null | head -1)
|
|
if [ -n "$pre" ]; then
|
|
printf '+%s &
|
|
' "$(cygpath -w "$pre")" >> $lib.rsp
|
|
added="$added$n "
|
|
fi
|
|
fi
|
|
done
|
|
# any extra compiled objs not in the 1995 list go last
|
|
for o in "$B/obj/$lib"/*.obj; do
|
|
n=$(basename "${o%.*}")
|
|
# btl4.obj (main) is linked bare, never a lib member (BTL4.MAK:70)
|
|
[ "$lib" = btl4 ] && [ "$n" = btl4 ] && continue
|
|
# l4tstall = the engine TEST main -- its own exe in 1995, never a lib member
|
|
[ "$n" = l4tstall ] && continue
|
|
case "$added" in *" $n "*) continue;; esac
|
|
printf '+..\obj\%s\%s.obj &
|
|
' "$lib" "$n" >> $lib.rsp
|
|
done
|
|
sed -i '$ s/ &$//' $lib.rsp
|
|
MSYS2_ARG_CONV_EXCL='*' tlib $lib.lib /P32 @$lib.rsp > $lib.tlib.log 2>&1
|
|
echo "$lib.lib: $(grep -c '^+' $lib.rsp) members ($(ls -la $lib.lib 2>/dev/null | awk '{print $5}') bytes)"
|
|
done
|
|
}
|
|
|
|
stage_link() {
|
|
cd "$B"
|
|
if [ -f obj/btl4/btl4.obj ]; then
|
|
MAIN=obj/btl4/btl4.obj
|
|
elif [ -f probe_main.cpp ]; then
|
|
bcc32 $FLAGS -I"$INC" -oprobe_main.obj probe_main.cpp > probe_main.log 2>&1 || { echo "probe main FAILED (probe_main.log)"; return 1; }
|
|
MAIN=probe_main.obj
|
|
fi
|
|
cp -f "$T/CODE/BT/32STUB.EXE" 32stub.exe 2>/dev/null
|
|
# single-line sections; SOSDBXC+SOSMBXC = the 32-bit Borland SOS pair
|
|
# (SOSMW* is 16-bit); WATTCPLG is the 16-bit NetNub TSR side -- excluded
|
|
cat > link.rsp <<EOF2
|
|
$(cygpath -w $C/C0X32.OBJ) $(cygpath -w "$B/$MAIN"), btl4opt.exe, btl4opt.map, lib\\munga.lib lib\\mungal4.lib $(cygpath -w $R/MUNGA_L4/libDPL/LIBDPL.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSDBXC.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSMBXC.LIB) lib\\bt.lib lib\\btl4.lib $(cygpath -w $R/DPMI32.LIB) $(cygpath -w $R/CW32.LIB)
|
|
EOF2
|
|
MSYS2_ARG_CONV_EXCL='*' tlink32 -Tpe -ax -m -L"$(cygpath -w $TW/BORLAND/BC45/LIB)" @link.rsp > link.log 2>&1
|
|
grep -i "unresolved" link.log | sed "s/^.*Error: //" | sort -u > UNRESOLVED.txt
|
|
echo "link exit: $? ; unresolved: $(wc -l < UNRESOLVED.txt) (build410/UNRESOLVED.txt); main=$MAIN"
|
|
ls -la btl4opt.exe 2>/dev/null
|
|
}
|
|
|
|
case "${1:-all}" in
|
|
engine) stage_engine;;
|
|
bt) stage_bt;;
|
|
libs) stage_libs;;
|
|
link) stage_link;;
|
|
status) for d in munga mungal4 bt btl4; do echo "$d: $(ls "$B/obj/$d"/*.obj 2>/dev/null | wc -l) objs"; done;;
|
|
all) stage_engine; stage_bt; stage_libs; stage_link;;
|
|
esac
|