Steam BUILD GATE: same-zip lobbies only (#108 confound killer)

Mixed-build lobbies silently corrupt raw-struct replication (night-9: one
stale-zip player, one desynced stream, ghost mechs + K/D doubt). Three
additive edits in btl4lobby.cpp:

1. HOST stamps the lobby with its exact build (btl4ver = BT_VERSION_STRING).
2. JOINER's lobby search filters on build equality -- a stale-zip player
   simply finds no lobby, and the "no lobby found" log line NAMES the local
   build so the report is self-diagnosing (#68's silent-exit lesson).
3. Post-entry verify (covers invites/direct joins + unstamped older hosts):
   mismatch -> log both versions loudly, LeaveLobby, fail the join.

LAN/relay (join.bat) handshake remains a separate 717 item -- this covers
the Steam path the operator asked about.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-04 11:24:05 -05:00
co-authored by Claude Fable 5
parent 15a1cf5d32
commit 22f732fcfb
+31 -1
View File
@@ -13,6 +13,7 @@
#pragma pack(push, 8)
#include "steam/steam_api.h"
#include "steam/isteammatchmaking.h"
#include <btversion.h> // BUILD GATE (#108 confound): exact-build lobbies
#pragma pack(pop)
//
@@ -346,6 +347,12 @@ int
}
currentLobby = created.m_ulSteamIDLobby;
SteamMatchmaking()->SetLobbyData(currentLobby, "btl4", "1");
// BUILD GATE: stamp the host's exact build on the lobby. Joiners filter
// on equality (below) and verify after entry -- a mixed-build lobby
// silently corrupts raw-struct replication (the night-9 ghost confound:
// one stale-zip player desyncs one connection's stream). Same build or
// no entry.
SteamMatchmaking()->SetLobbyData(currentLobby, "btl4ver", BT_VERSION_STRING);
PublishSelf(pilot_name, vehicle, color, experience);
LobbyLog("host: lobby up (%llu)", (unsigned long long)created.m_ulSteamIDLobby);
@@ -427,6 +434,11 @@ int
ISteamMatchmaking *matchmaking = SteamMatchmaking();
matchmaking->AddRequestLobbyListStringFilter(
"btl4", "1", k_ELobbyComparisonEqual);
// BUILD GATE: only lobbies stamped with OUR exact build are visible. A
// stale-zip player finds nothing -- and the log names the build so the
// "no lobby found" report is self-diagnosing (#68's silent-exit lesson).
matchmaking->AddRequestLobbyListStringFilter(
"btl4ver", BT_VERSION_STRING, k_ELobbyComparisonEqual);
SteamAPICall_t call = matchmaking->RequestLobbyList();
LobbyMatchList_t match_list;
memset(&match_list, 0, sizeof(match_list));
@@ -434,7 +446,9 @@ int
LobbyMatchList_t::k_iCallback, 15000) != 0 ||
match_list.m_nLobbiesMatching == 0)
{
LobbyLog("join: no btl4 lobby found");
LobbyLog("join: no btl4 lobby found for build %s "
"(a lobby on a DIFFERENT build is invisible by design -- "
"host and joiners must run the same zip)", BT_VERSION_STRING);
return -1;
}
@@ -450,6 +464,22 @@ int
return -1;
}
currentLobby = lobby;
// BUILD GATE belt-and-suspenders: the list filter covers discovery, but
// verify the entered lobby too (covers invite/direct joins and any
// filter drift). Mismatch = leave loudly, never play version-skewed.
{
const char *host_ver = matchmaking->GetLobbyData(currentLobby, "btl4ver");
if (host_ver == NULL || strcmp(host_ver, BT_VERSION_STRING) != 0)
{
LobbyLog("join: BUILD MISMATCH -- host runs %s, this machine runs %s; "
"leaving (both sides must run the same zip)",
(host_ver && *host_ver) ? host_ver : "<unstamped/older>",
BT_VERSION_STRING);
matchmaking->LeaveLobby(currentLobby);
currentLobby = CSteamID();
return -1;
}
}
PublishSelf(pilot_name, vehicle, color, experience);
LobbyLog("join: in lobby, waiting for GO");