The three build dirs (build\ pod, build-glass\, build-steam\) were compile-
time splits of the same game; the tax was real: a stale steam exe shipped 2
days behind, the felt keymap flipped with the boot flavor, and cockpit
clicks were silently dead in the pod build (the trigger-config incident).
Now everything compiles into the single build\ exe:
- CMakeLists: BT_GLASS/BT_STEAM options removed; the glass TUs (PadRIO,
bindings, panel, glass windows, plasma) + FE/console + Steam transport
compile unconditionally; both macros always defined (seam markers).
- Steam: steam_api.lib linked with /DELAYLOAD:steam_api.dll + delayimp --
the DLL maps only when SteamAPI is first called, and every call site
gates on BT_STEAM_NET=1 (BTSteamNet_* short-circuit on steamActive), so
machines without the DLL run everything but Steam sessions.
- CABINET GUARD (btl4main): the miniconsole menu previously claimed any
zero-arg launch -- unified, that would hijack the pod cabinet's boot
shape. The menu now requires BT_PLATFORM=glass (or BT_FE_MENU=1);
platform parse moved above the fe_menu_mode computation. A bare boot
behaves exactly like the old pod build (DEV profile, wait for egg).
- Bats (play_solo/join/join_lan/play_steam) + the btoperator.py template:
single build\ path + BT_PLATFORM=glass. mkdist: one exe (+DLL scan
picks up OpenAL32 + steam_api). build-glass\/build-steam\/build-glass2\
(a stale Jul-20 cache) deleted.
Verified matrix on the unified exe:
bare zero-arg boot == old pod exe (same DEV profile + egg-load path;
the segfault on a missing egg is pre-existing, baselined vs the zip exe)
glass + BT_BTNTEST scripted click -> [cfgmap] ENTER/EXIT (trigger config)
runs with steam_api.dll ABSENT (delay-load proven)
glass zero-arg -> miniconsole menu
2-node loopback MP: 145 ticks each, cross-connected
BT_STEAM_NET=1 without Steam client -> "staying on Winsock", game runs
KB: context/glass-cockpit.md compile-gates section rewritten for the
unified model.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
93 lines
3.6 KiB
Python
93 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""mkdist.py -- build the tester-distribution zip.
|
|
|
|
Layout (matches what the player bats expect):
|
|
BT411-<date>-<hash>/
|
|
play_solo.bat join.bat join_lan.bat (from players/)
|
|
build/Release/btl4.exe (pod build -- fallback)
|
|
build-glass/Release/btl4.exe (preferred: clickable cockpit)
|
|
content/... (git-TRACKED files only --
|
|
the working tree carries dev
|
|
junk that must not ship)
|
|
|
|
The bats prefer build-glass when present and set BT_PLATFORM=glass with it,
|
|
so testers boot the glass experience (PadRIO clicks, trigger config,
|
|
bindings.txt keymap) with the pod build as fallback.
|
|
|
|
Usage: python tools/mkdist.py [outdir] (default outdir = dist/)
|
|
"""
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import zipfile
|
|
|
|
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
def main():
|
|
os.chdir(REPO)
|
|
outdir = sys.argv[1] if len(sys.argv) > 1 else os.path.join(REPO, "dist")
|
|
os.makedirs(outdir, exist_ok=True)
|
|
|
|
# Name by the repo version convention (BT411_4.11.NNN, tools/btversion.cmake:
|
|
# build = commit count). Falls back to date+hash if the header is absent.
|
|
name = None
|
|
for h in ("build/btversion.h", "build-glass/btversion.h"):
|
|
if os.path.exists(h):
|
|
m = re.search(r'BT_VERSION_STRING\s+"([^"]+)"', open(h).read())
|
|
if m:
|
|
name = "BT411_" + m.group(1)
|
|
break
|
|
if name is None:
|
|
githash = subprocess.check_output(
|
|
["git", "rev-parse", "--short", "HEAD"]).decode().strip()
|
|
name = "BT411-%s-%s" % (time.strftime("%Y-%m-%d"), githash)
|
|
zpath = os.path.join(outdir, name + ".zip")
|
|
|
|
tracked = subprocess.check_output(
|
|
["git", "ls-files", "-z", "content/"]).decode().split("\0")
|
|
tracked = [t for t in tracked if t]
|
|
|
|
# ONE unified build (2026-07-21): every layer (pod game + glass cockpit +
|
|
# Steam transport) lives in the single exe; steam_api.dll is delay-loaded.
|
|
exes = ["build/Release/btl4.exe"]
|
|
bats = ["players/play_solo.bat", "players/join.bat", "players/join_lan.bat",
|
|
"players/play_steam.bat"]
|
|
for p in exes + bats:
|
|
if not os.path.exists(p):
|
|
sys.exit("MISSING: %s -- build/refresh it first" % p)
|
|
|
|
# Runtime DLLs living next to each exe (OpenAL32.dll etc.) -- the exe
|
|
# fails to load without them (caught by the clean-extract boot test).
|
|
for exe in list(exes):
|
|
d = os.path.dirname(exe)
|
|
for f in sorted(os.listdir(d)):
|
|
if f.lower().endswith(".dll"):
|
|
exes.append(d + "/" + f)
|
|
|
|
total = 0
|
|
with zipfile.ZipFile(zpath, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as z:
|
|
for p in bats: # bats at the zip ROOT (next to
|
|
arc = os.path.basename(p) # content\ + build\, per the guard)
|
|
z.write(p, name + "/" + arc)
|
|
total += os.path.getsize(p)
|
|
for p in exes:
|
|
z.write(p, name + "/" + p)
|
|
total += os.path.getsize(p)
|
|
for p in tracked:
|
|
if not os.path.exists(p):
|
|
print(" (skipping tracked-but-absent: %s)" % p)
|
|
continue
|
|
z.write(p, name + "/" + p)
|
|
total += os.path.getsize(p)
|
|
|
|
zsz = os.path.getsize(zpath)
|
|
print("wrote %s" % zpath)
|
|
print(" %d files, %.1f MB raw -> %.1f MB zipped"
|
|
% (len(bats) + len(exes) + len(tracked), total / 1048576.0,
|
|
zsz / 1048576.0))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|