lan mods: say WHY a MODOK report was dropped

A host whose seat never goes ready showed 'LAN rx MOTK5 MODOK' every 2 s and
nothing else, while the guest resent forever because the host's echo never
agreed. The MODOK handler has three early exits before its own trace — two
parse failures and a failed ae_np_read_lan_state — so the one case the trace
cannot explain is precisely the one that reaches none of it.

Name the reason on each, rate-limited to 3 s. The read-lan-state case also
points at the likely cause: ae_np_lan_file() is resolved against the process
working directory, so a host launched from a different cwd than the one that
wrote netplay_lan_lobby.txt reads nothing and rejects every peer report.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UoSNLFj7kvarYHEV9PCZpV
This commit is contained in:
Alex Vanderveen
2026-08-21 17:49:00 -04:00
parent c445f75ce4
commit d04f4fed73
+29 -3
View File
@@ -10852,18 +10852,44 @@ namespace {
/* Guest -> host: "I can (not) run the session's mods". */
if (std::strncmp(buf, "MOTK5 MODOK\n", 12) == 0 &&
g_lnch_hosting_lan) {
/* Rate-limited reason trace for the THREE early exits below.
* The trace further down was added because "no output" was
* ambiguous — but it sits after these continues, so the one
* case it cannot explain is a MODOK that never reaches it.
* That is exactly what a host shows when the seat never goes
* ready: 'LAN rx MOTK5 MODOK' every 2 s, nothing else, and a
* guest resending forever because the echo never agrees. */
auto modok_drop = [](const char* why) {
static uint32_t s_last_ms = 0;
const uint32_t nowm = (uint32_t)SDL_GetTicks64();
if (nowm - s_last_ms <= 3000u) return;
s_last_ms = nowm;
std::fprintf(stderr,
"psxrecomp: LAN mods: MODOK DROPPED (%s) — seat stays "
"not-ready and the guest will resend forever\n", why);
std::fflush(stderr);
};
char* p = buf + 12;
char* nl = std::strchr(p, '\n');
if (!nl) continue;
if (!nl) { modok_drop("malformed: no newline after player id"); continue; }
*nl = '\0';
const std::string pid = p;
p = nl + 1;
nl = std::strchr(p, '\n');
if (!nl) continue;
if (!nl) { modok_drop("malformed: no newline after ok flag"); continue; }
*nl = '\0';
const int peer_ok = std::atoi(p) ? 1 : 0;
AeLanLobbyState st;
if (!ae_np_read_lan_state(&st)) continue;
if (!ae_np_read_lan_state(&st)) {
/* The lobby state is the file ae_np_lan_file() writes next
* to the CURRENT WORKING DIRECTORY, so a host launched
* from a different cwd than the one that wrote it reads
* nothing and silently rejects every peer's report. */
modok_drop("ae_np_read_lan_state failed — no LAN lobby "
"state (check netplay_lan_lobby.txt in the "
"process working directory)");
continue;
}
const int slot = ae_np_lan_find_slot_by_id(st, pid.c_str());
{
/* Unconditional (rate-limited) trace: "no output" was