diff --git a/game/glass/btl4lobby.cpp b/game/glass/btl4lobby.cpp index 482d5b6..b86242d 100644 --- a/game/glass/btl4lobby.cpp +++ b/game/glass/btl4lobby.cpp @@ -49,6 +49,50 @@ static void } #include +// +// A rejection the PLAYER must see goes through LobbyNotice: the same text +// lands in the day log (newlines flattened so the line stays greppable) +// AND in a blocking message box. These paths are synchronous FE flows -- +// a bare return here QUITS the exe, and #68 taught us a player bounced +// with only a log line reports "the game just closed". +// +static void + LobbyNotice(const char *format, ...) +{ + char text[512]; + va_list arguments; + va_start(arguments, format); + _vsnprintf(text, sizeof(text) - 1, format, arguments); + text[sizeof(text) - 1] = 0; + va_end(arguments); + { + char flat[512]; + int n = 0; + for (const char *s = text; *s && n < 510; ++s) + { + if (*s == '\n') + { + if (n > 0 && flat[n - 1] == ' ') + continue; + flat[n++] = ' '; + } + else + { + flat[n++] = *s; + } + } + flat[n] = 0; + LobbyLog("NOTICE: %s", flat); + } + WCHAR wide[512]; + int n = 0; + for (const char *s = text; *s && n < 511; ++s) + wide[n++] = (WCHAR)*s; + wide[n] = 0; + MessageBoxW(NULL, wide, L"BATTLETECH -- STEAM LOBBY", + MB_OK | MB_ICONWARNING | MB_SETFOREGROUND); +} + //########################################################################### // Synchronous Steam call-result helper (manual polling -- no callback // template machinery in this C-style TU). @@ -458,7 +502,9 @@ int { if (BTSteamNet_Install() != 0 || !BTSteamNet_Active()) { - LobbyLog("join: Steam transport unavailable"); + LobbyNotice("STEAM UNAVAILABLE\n\n" + "Could not reach Steam.\n" + "Is Steam running and logged in?"); return -1; } @@ -477,9 +523,36 @@ int LobbyMatchList_t::k_iCallback, 15000) != 0 || match_list.m_nLobbiesMatching == 0) { - 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); + // + // Nothing on OUR build. Probe once WITHOUT the version filter so + // the rejection is specific: "the host is on a different zip" + // beats "no lobby" when one is in fact up. Lobby data rides back + // with the list result, readable without joining. (Filters only + // apply to the next request, so the probe re-adds the game key.) + // + matchmaking->AddRequestLobbyListStringFilter( + "btl4", "1", k_ELobbyComparisonEqual); + call = matchmaking->RequestLobbyList(); + memset(&match_list, 0, sizeof(match_list)); + if (WaitApiCall(call, &match_list, sizeof(match_list), + LobbyMatchList_t::k_iCallback, 8000) == 0 && + match_list.m_nLobbiesMatching > 0) + { + const char *host_ver = matchmaking->GetLobbyData( + matchmaking->GetLobbyByIndex(0), "btl4ver"); + LobbyNotice("BUILD MISMATCH\n\n" + "A lobby is up, but the host runs build %s\n" + "and this machine runs build %s.\n\n" + "Everyone must run the same zip to play together.", + (host_ver && *host_ver) ? host_ver : "(an older build)", + BT_VERSION_STRING); + } + else + { + LobbyNotice("NO LOBBY FOUND\n\n" + "No BattleTech lobby is up right now.\n" + "(This machine runs build %s.)", BT_VERSION_STRING); + } return -1; } @@ -502,12 +575,14 @@ int 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 : "", - BT_VERSION_STRING); matchmaking->LeaveLobby(currentLobby); currentLobby = CSteamID(); + LobbyNotice("BUILD MISMATCH\n\n" + "The host runs build %s\n" + "and this machine runs build %s.\n\n" + "Everyone must run the same zip to play together.", + (host_ver && *host_ver) ? host_ver : "(an older build)", + BT_VERSION_STRING); return -1; } } @@ -548,7 +623,15 @@ int LobbyLog("join: my token [%s], map [%s]", my_token_out, steam_map_out); if (my_token_out[0] == 0) { - result = -1; // the host's map is missing us + // The host launched without us -- no seat in the mission map. + // (Same-build clients can only hit this via a full lobby or a + // publish race now; version skew is gated before entry.) + LobbyNotice("LEFT BEHIND\n\n" + "The host launched the mission without this machine\n" + "(no seat in the mission map).\n\n" + "Rejoin on the next launch. If this repeats, compare\n" + "builds: this machine runs %s.", BT_VERSION_STRING); + result = -1; } } SteamMatchmaking()->LeaveLobby(currentLobby);