diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e0b03d..ee99cf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,18 +13,29 @@ set(DXSDK "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)" CACHE PATH #===========================================================================# # ONE BUILD (unified 2026-07-21; was pod / glass / steam compile splits). # Everything compiles into the single exe; behavior is selected at RUNTIME -# by env gates only -- BT_PLATFORM=glass arms the desktop-cockpit profile -# (PadRIO clicks, bindings.txt keymap, plasma window, miniconsole menu), -# BT_STEAM_NET=1 arms the Steam transport (steam_api.dll is DELAY-LOADED, -# so machines without the DLL run fine while the gate stays off). A bare -# boot (no env, no args) behaves like the old pod build: DEV profile, no -# menu, waits for the console egg -- the cabinet default is unchanged. -# The BT_GLASS/BT_STEAM macros remain (always defined) as seam markers. +# by env gates -- BT_PLATFORM=glass arms the desktop-cockpit profile +# (PadRIO clicks, bindings.txt keymap, plasma window, miniconsole menu). +# A bare boot (no env, no args) behaves like the old pod build: DEV +# profile, no menu, waits for the console egg -- the cabinet default is +# unchanged. The BT_GLASS macro remains (always defined) as a seam marker. +# +# THE ONE COMPILE GATE: BT_STEAM (default OFF). The Steamworks SDK's +# license means a RELEASE build must exclude Steam entirely (no SDK +# headers, no steam_api.lib, no DLL). When ON: the transport compiles in, +# steam_api.dll is DELAY-LOADED, and BT_STEAM_NET=1 arms it at runtime -- +# machines without the DLL still run everything else. +# Dev checkout: configure build/ once with -DBT_STEAM=ON. #===========================================================================# +option(BT_STEAM "Steam transport + lobby (Steamworks SDK -- EXCLUDE from public releases)" OFF) +message(STATUS "bt411: BT_STEAM=${BT_STEAM}") + set(BT_DEFS WIN32 _WINDOWS UNICODE _UNICODE NOMINMAX _CRT_SECURE_NO_DEPRECATE _CRT_SECURE_NO_WARNINGS _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS - BT_GLASS BT_STEAM) + BT_GLASS) +if(BT_STEAM) + list(APPEND BT_DEFS BT_STEAM) +endif() set(BT_OPTS /permissive /W0 /wd4996 /EHsc /bigobj /MP) #===========================================================================# @@ -368,24 +379,28 @@ target_link_libraries(btl4 PRIVATE # UNRESOLVED tolerates the dead offline-tool factory in mech3.cpp. See docs. target_link_options(btl4 PRIVATE /FORCE) -# Steam transport: compiled in, DELAY-LOADED. steam_api.dll is only mapped -# when the first SteamAPI call runs, and every call site gates on -# BT_STEAM_NET=1 (btl4main step-4b bring-up; L4NET's BTSteamNet_* short- -# circuit on steamActive) -- so a machine without the DLL runs everything -# except Steam sessions. -set(STEAMWORKS "${CMAKE_SOURCE_DIR}/extern/steamworks_sdk_164") -target_sources(munga_engine PRIVATE "engine/MUNGA_L4/L4STEAMNET.cpp") -target_sources(btl4 PRIVATE "game/glass/btl4lobby.cpp") -target_include_directories(munga_engine PRIVATE "${STEAMWORKS}/public") -target_include_directories(btl4 PRIVATE "${STEAMWORKS}/public") -target_link_libraries(btl4 PRIVATE - "${STEAMWORKS}/redistributable_bin/steam_api.lib" - delayimp) -target_link_options(btl4 PRIVATE "/DELAYLOAD:steam_api.dll") -add_custom_command(TARGET btl4 POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${STEAMWORKS}/redistributable_bin/steam_api.dll" - "$") +# Steam transport (BT_STEAM=ON only -- the license gate): DELAY-LOADED. +# steam_api.dll is only mapped when the first SteamAPI call runs, and every +# call site gates on BT_STEAM_NET=1 (btl4main step-4b bring-up; L4NET's +# BTSteamNet_* short-circuit on steamActive) -- so even the steam-enabled +# exe runs without the DLL as long as the env gate stays off. A BT_STEAM=OFF +# configure touches NO Steamworks bits: no SDK headers, no lib, no DLL copy +# (and mkdist then leaves play_steam.bat + steam_api.dll out of the zip). +if(BT_STEAM) + set(STEAMWORKS "${CMAKE_SOURCE_DIR}/extern/steamworks_sdk_164") + target_sources(munga_engine PRIVATE "engine/MUNGA_L4/L4STEAMNET.cpp") + target_sources(btl4 PRIVATE "game/glass/btl4lobby.cpp") + target_include_directories(munga_engine PRIVATE "${STEAMWORKS}/public") + target_include_directories(btl4 PRIVATE "${STEAMWORKS}/public") + target_link_libraries(btl4 PRIVATE + "${STEAMWORKS}/redistributable_bin/steam_api.lib" + delayimp) + target_link_options(btl4 PRIVATE "/DELAYLOAD:steam_api.dll") + add_custom_command(TARGET btl4 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${STEAMWORKS}/redistributable_bin/steam_api.dll" + "$") +endif() # Copy the OpenAL runtime DLL next to the built exe. (libsndfile is gone: its # repo DLL was a no-op STUB -- L4AUDRES now loads the soundbank WAVs with an diff --git a/context/glass-cockpit.md b/context/glass-cockpit.md index 968958a..d442a30 100644 --- a/context/glass-cockpit.md +++ b/context/glass-cockpit.md @@ -27,9 +27,17 @@ version skew (a stale steam exe shipped 2 days behind), tripled build time, and | `BT_STEAM_NET=1` | the Steam transport (FakeIP/SDR; degrades to Winsock without the Steam client). `steam_api.dll` is **DELAY-LOADED** (`/DELAYLOAD` + delayimp) — machines without the DLL run everything else | | (nothing) | the old pod-build behavior byte-for-byte: DEV profile, no menu, waits for the console egg — **the cabinet default is unchanged** | -- The `BT_GLASS`/`BT_STEAM` macros are now ALWAYS defined (seam markers only — the `#ifdef` - sites remain as documentation of the layer boundaries). Every gated code path was audited: - all are instance-guarded (`PadRIO::activeInstance`, `steamActive`) or env-gated at runtime. +- The `BT_GLASS` macro is now ALWAYS defined (a seam marker only — the `#ifdef` sites remain + as documentation of the layer boundary). Every gated code path was audited: all are + instance-guarded (`PadRIO::activeInstance`, `steamActive`) or env-gated at runtime. +- **`BT_STEAM` stays a COMPILE gate (the LICENSE gate, default OFF, restored 2026-07-21):** + the Steamworks SDK terms bar a public release with Steam inside, so a release configure + must be able to exclude it entirely — no SDK headers, no `steam_api.lib`, no DLL. The dev + checkout configures `build/` once with `-DBT_STEAM=ON`. `mkdist.py` reads the answer from + `build/CMakeCache.txt`: steam-OFF zips carry no `play_steam.bat`, no `steam_api.dll` + (including a STALE one from an earlier ON build), a README with the steam section stripped, + and a `-nosteam` name suffix so the two flavors never clobber. Verified both flavors: + OFF exe has no steam bits + `BT_STEAM_NET=1` is inert; ON exe degrades to Winsock. - **Menu guard (cabinet protection):** the miniconsole previously claimed any zero-arg launch; unified, it requires `BT_PLATFORM=glass` (or `BT_FE_MENU=1`) — a bare cabinet boot can never land in the menu (btl4main.cpp, platform parse moved above the fe_menu_mode computation). diff --git a/players/README.txt b/players/README.txt index 3301c62..654050a 100644 --- a/players/README.txt +++ b/players/README.txt @@ -9,8 +9,8 @@ TO JOIN AN INTERNET GAME: double-click join.bat (waits for the operator's session if it's not up yet) TO JOIN A LAN GAME: double-click join_lan.bat (operator's LAN) SINGLE-PLAYER PRACTICE: double-click play_solo.bat (no network) -STEAM INTERNET PLAY: double-click play_steam.bat (EXPERIMENTAL -- - needs the Steam client running; host or join from the menu) +{STEAM}STEAM INTERNET PLAY: double-click play_steam.bat (EXPERIMENTAL -- +{STEAM} needs the Steam client running; host or join from the menu) Your seat and mech are assigned automatically by the operator. If the game closes unexpectedly, send the operator content\join.log. diff --git a/tools/mkdist.py b/tools/mkdist.py index 1293d1c..3c4e6a9 100644 --- a/tools/mkdist.py +++ b/tools/mkdist.py @@ -43,17 +43,31 @@ def main(): 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. + # ONE unified build (2026-07-21): every layer lives in the single exe. + # THE LICENSE GATE: BT_STEAM is compile-time (Steamworks SDK terms bar a + # public release with Steam inside). Read the configure's answer from + # the CMake cache; a steam-OFF zip must carry neither play_steam.bat nor + # steam_api.dll (a stale DLL can linger from an earlier ON build). + steam_on = False + try: + cache = open("build/CMakeCache.txt", encoding="utf-8", errors="ignore").read() + steam_on = "BT_STEAM:BOOL=ON" in cache + except OSError: + pass + print(" BT_STEAM=%s (from build/CMakeCache.txt)" % ("ON" if steam_on else "OFF")) + if not steam_on: + name += "-nosteam" # distinct name: never clobbers the dev-flavor zip + zpath = os.path.join(outdir, name + ".zip") + exes = ["build/Release/btl4.exe"] - bats = ["players/play_solo.bat", "players/join.bat", "players/join_lan.bat", - "players/play_steam.bat"] + bats = ["players/play_solo.bat", "players/join.bat", "players/join_lan.bat"] + if steam_on: + bats.append("players/play_steam.bat") for p in exes + bats: if not os.path.exists(p): sys.exit("MISSING: %s -- build/refresh it first" % p) @@ -63,8 +77,12 @@ def main(): 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) + if not f.lower().endswith(".dll"): + continue + if f.lower() == "steam_api.dll" and not steam_on: + print(" (steam OFF: leaving stale %s out of the zip)" % f) + continue + exes.append(d + "/" + f) # System runtime DLLs the exe needs on a bare tester machine (32-bit # d3dx9 + MSVC runtimes -- carried in redist/, shipped next to the exe; @@ -79,6 +97,12 @@ def main(): if os.path.exists("players/README.txt"): readme = open("players/README.txt", encoding="utf-8").read() readme = readme.replace("{VERSION}", name.replace("BT411_", "")) + lines = readme.splitlines(True) + if steam_on: # keep steam lines, drop marker + lines = [l.replace("{STEAM}", "") for l in lines] + else: # steam-free zip: strip them + lines = [l for l in lines if "{STEAM}" not in l] + readme = "".join(lines) z.writestr(name + "/README.txt", readme) for p in bats: # bats at the zip ROOT (next to arc = os.path.basename(p) # content\ + build\, per the guard)