BT_EXPIRE: tester builds stop working 14 days after build (compile gate)
Distributed test zips go stale and stray. BT_EXPIRE (CMake option,
DEFAULT ON so a zip can never accidentally ship without it) makes the
exe refuse to start BT_EXPIRE_DAYS (default 14) after its build day:
boot logs the remaining window, an expired build logs + shows a
"test build expired -- ask the operator for the current build" box and
exits. btversion.h now stamps BT_BUILD_UNIX (UTC-midnight-rounded so
the only-on-change header churns once per day, not every build) +
BT_BUILD_DATE. Dev is unaffected: every build re-stamps the day.
-DBT_EXPIRE=OFF builds a non-expiring exe; mkdist reads the cache and
marks such a zip "-noexpire" + prints a warning, and the tester README
expiry note is {EXPIRE}-marker-gated like the steam lines. Second
compile-gate exception after BT_STEAM (convention updated in
glass-cockpit.md). Quality gate, not DRM -- a clock rollback defeats it.
Verified live: default build logs "test build window: 14 day(s) left";
a -DBT_EXPIRE_DAYS=0 build logs TEST BUILD EXPIRED and parks on the
explanation box (window title checked) without starting the game;
restored to 14 and rebuilt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
753540de96
commit
eb618fe9e6
@@ -29,6 +29,19 @@ set(DXSDK "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)" CACHE PATH
|
||||
option(BT_STEAM "Steam transport + lobby (Steamworks SDK -- EXCLUDE from public releases)" OFF)
|
||||
message(STATUS "bt411: BT_STEAM=${BT_STEAM}")
|
||||
|
||||
#===========================================================================#
|
||||
# Tester-build expiry tripwire (2026-07-22). Distributed test zips go stale
|
||||
# and stray: with BT_EXPIRE on (the DEFAULT, so a zip can never accidentally
|
||||
# ship without it) the exe refuses to start BT_EXPIRE_DAYS after its build
|
||||
# date, telling the tester to fetch a current build. Dev is unaffected --
|
||||
# btversion.h re-stamps the build day on every build. Disable for a
|
||||
# non-expiring build with -DBT_EXPIRE=OFF (mkdist marks such a zip
|
||||
# '-noexpire'). Quality gate, not DRM -- a clock rollback defeats it.
|
||||
#===========================================================================#
|
||||
option(BT_EXPIRE "Expire the exe BT_EXPIRE_DAYS after its build date" ON)
|
||||
set(BT_EXPIRE_DAYS 14 CACHE STRING "Days a BT_EXPIRE build keeps running")
|
||||
message(STATUS "bt411: BT_EXPIRE=${BT_EXPIRE} (${BT_EXPIRE_DAYS} days)")
|
||||
|
||||
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
|
||||
@@ -366,6 +379,9 @@ target_sources(btl4 PRIVATE
|
||||
)
|
||||
target_include_directories(btl4 BEFORE PRIVATE "${CMAKE_SOURCE_DIR}/game/glass")
|
||||
target_compile_definitions(btl4 PRIVATE ${BT_DEFS})
|
||||
if(BT_EXPIRE)
|
||||
target_compile_definitions(btl4 PRIVATE BT_EXPIRE=1 BT_EXPIRE_DAYS=${BT_EXPIRE_DAYS})
|
||||
endif()
|
||||
target_compile_options(btl4 PRIVATE ${BT_OPTS})
|
||||
target_link_libraries(btl4 PRIVATE
|
||||
bt410_l4
|
||||
|
||||
@@ -49,9 +49,16 @@ version skew (a stale steam exe shipped 2 days behind), tripled build time, and
|
||||
glass + scripted click → ConfigureMappables end-to-end; exe runs WITHOUT steam_api.dll
|
||||
present; glass zero-arg → menu; 2-node loopback MP (145 ticks each); `BT_STEAM_NET=1`
|
||||
without Steam → "staying on Winsock" + game runs.
|
||||
- **Convention:** every `BT_*` name is a RUNTIME env gate (`BTEnvOn`) — with the single
|
||||
exception of `BT_STEAM`, the license compile gate above. Do not add another compile gate
|
||||
without updating this file.
|
||||
- **Convention:** every `BT_*` name is a RUNTIME env gate (`BTEnvOn`) — with TWO exceptions,
|
||||
both compile gates: `BT_STEAM` (the license gate above) and **`BT_EXPIRE` (2026-07-22, the
|
||||
tester-build expiry tripwire)** — default ON, the exe refuses to start `BT_EXPIRE_DAYS`
|
||||
(default 14) after its build DAY (`btversion.h BT_BUILD_UNIX`, UTC-midnight-rounded so the
|
||||
only-on-change header churns once per day, not per build). Boot logs `[boot] test build
|
||||
window: N day(s) left`; expired = log + MessageBox + exit. Disable: `-DBT_EXPIRE=OFF`
|
||||
(mkdist marks such a zip `-noexpire` + warns; README expiry note is `{EXPIRE}`-marker-gated).
|
||||
Quality gate, not DRM — a clock rollback defeats it. Verified both paths live
|
||||
(`-DBT_EXPIRE_DAYS=0` force-expire run). Do not add another compile gate without updating
|
||||
this file.
|
||||
- No weak-linkage/optional symbols — `/FORCE` turns unresolved externals into runtime AVs
|
||||
([[reconstruction-gotchas]]); everything links always, so this class of trap no longer varies
|
||||
by build flavor.
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime> // BT_EXPIRE tripwire (time)
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -542,6 +543,39 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
std::cout << "BattleTech " << BT_VERSION_FULL
|
||||
<< " (win32 reconstruction of Tesla 4.10)" << std::endl << std::flush;
|
||||
|
||||
#ifdef BT_EXPIRE
|
||||
// TESTER-BUILD EXPIRY TRIPWIRE (compile gate BT_EXPIRE, default ON --
|
||||
// see CMakeLists). Distributed zips go stale and stray; refuse to run
|
||||
// BT_EXPIRE_DAYS after the build day (btversion.h BT_BUILD_UNIX, UTC
|
||||
// midnight). Dev builds re-stamp every build, so this never fires
|
||||
// locally. Quality gate, not DRM.
|
||||
{
|
||||
const time_t expires = (time_t)BT_BUILD_UNIX
|
||||
+ (time_t)BT_EXPIRE_DAYS * 86400;
|
||||
const time_t now = time(0);
|
||||
if (now >= expires)
|
||||
{
|
||||
std::cout << "[boot] TEST BUILD EXPIRED (built " << BT_BUILD_DATE
|
||||
<< ", " << BT_EXPIRE_DAYS << "-day test window)"
|
||||
<< std::endl << std::flush;
|
||||
char expired_text[256];
|
||||
sprintf(expired_text,
|
||||
"This BattleTech test build (%s, built %s) has expired.\n\n"
|
||||
"Test builds stop working %d days after they are made so\n"
|
||||
"stale copies don't wander around.\n\n"
|
||||
"Ask the operator for the current build.",
|
||||
BT_VERSION_STRING, BT_BUILD_DATE, (int)BT_EXPIRE_DAYS);
|
||||
MessageBoxA(NULL, expired_text,
|
||||
"BattleTech -- test build expired", MB_OK | MB_ICONWARNING);
|
||||
return 0;
|
||||
}
|
||||
int days_left = (int)((expires - now + 86399) / 86400);
|
||||
std::cout << "[boot] test build window: " << days_left
|
||||
<< " day(s) left (built " << BT_BUILD_DATE << ")"
|
||||
<< std::endl << std::flush;
|
||||
}
|
||||
#endif
|
||||
|
||||
// CPU pin (timing stability). BT_AFFINITY overrides the mask; =0 disables --
|
||||
// required for multi-instance runs (two instances pinned to core 0 starve
|
||||
// each other, and the L4NET connect-retry loop busy-waits).
|
||||
|
||||
@@ -43,3 +43,5 @@ An Xbox controller works out of the box. Rebind keys in
|
||||
content\bindings.txt (regenerates with defaults if deleted).
|
||||
|
||||
This build: {VERSION}. Private -- do not redistribute.
|
||||
{EXPIRE}Test builds STOP WORKING 14 days after they are made -- if the game
|
||||
{EXPIRE}says it has expired, just grab the operator's newest zip.
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
#
|
||||
# Invoked: cmake -DOUT=<header> -DSRC=<repo root> -P btversion.cmake
|
||||
|
||||
# Build DAY stamp (UTC midnight epoch) for the tester-build expiry tripwire
|
||||
# (BT_EXPIRE). Day precision on purpose: the header is written only-on-change,
|
||||
# so a per-second stamp would churn btl4main.obj on every no-op build.
|
||||
string(TIMESTAMP BT_NOW_UNIX "%s" UTC)
|
||||
math(EXPR BT_BUILD_UNIX "(${BT_NOW_UNIX} / 86400) * 86400")
|
||||
string(TIMESTAMP BT_BUILD_DATE "%Y-%m-%d" UTC)
|
||||
|
||||
execute_process(COMMAND git rev-list --count HEAD
|
||||
WORKING_DIRECTORY "${SRC}"
|
||||
OUTPUT_VARIABLE BT_BUILD OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
@@ -44,6 +51,8 @@ set(CONTENT "// generated by tools/btversion.cmake -- do not edit, not in git
|
||||
#define BT_VERSION_STRING \"4.11.${BT_BUILD}\"
|
||||
#define BT_VERSION_HASH \"${BT_HASH}${BT_DIRTY}\"
|
||||
#define BT_VERSION_FULL \"4.11.${BT_BUILD} (${BT_HASH}${BT_DIRTY})\"
|
||||
#define BT_BUILD_UNIX ${BT_BUILD_UNIX}
|
||||
#define BT_BUILD_DATE \"${BT_BUILD_DATE}\"
|
||||
")
|
||||
|
||||
# write only when changed so incremental builds don't churn
|
||||
|
||||
@@ -54,6 +54,7 @@ def main():
|
||||
# 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
|
||||
cache = ""
|
||||
try:
|
||||
cache = open("build/CMakeCache.txt", encoding="utf-8", errors="ignore").read()
|
||||
steam_on = "BT_STEAM:BOOL=ON" in cache
|
||||
@@ -62,6 +63,15 @@ def main():
|
||||
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
|
||||
|
||||
# TESTER-BUILD EXPIRY (BT_EXPIRE, default ON): a zip cut from an
|
||||
# expire-OFF build never dies in the field -- mark it loudly so it is a
|
||||
# deliberate act, not an accident.
|
||||
expire_on = "BT_EXPIRE:BOOL=ON" in cache if cache else True
|
||||
print(" BT_EXPIRE=%s (from build/CMakeCache.txt)" % ("ON" if expire_on else "OFF"))
|
||||
if not expire_on:
|
||||
name += "-noexpire"
|
||||
print(" WARNING: this zip NEVER EXPIRES -- intended for distribution?")
|
||||
zpath = os.path.join(outdir, name + ".zip")
|
||||
|
||||
exes = ["build/Release/btl4.exe"]
|
||||
@@ -102,6 +112,10 @@ def main():
|
||||
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]
|
||||
if expire_on: # same treatment for expiry note
|
||||
lines = [l.replace("{EXPIRE}", "") for l in lines]
|
||||
else:
|
||||
lines = [l for l in lines if "{EXPIRE}" not in l]
|
||||
readme = "".join(lines)
|
||||
z.writestr(name + "/README.txt", readme)
|
||||
for p in bats: # bats at the zip ROOT (next to
|
||||
|
||||
Reference in New Issue
Block a user