diff --git a/MUNGA_L4/L4NET.CPP b/MUNGA_L4/L4NET.CPP index 3a80028..d0ca059 100644 --- a/MUNGA_L4/L4NET.CPP +++ b/MUNGA_L4/L4NET.CPP @@ -1198,6 +1198,34 @@ void L4NetworkManager::Send( our_host_manager = application->GetHostManager(); Check(our_host_manager); base_host = our_host_manager->GetRemoteHost(host_ID); + + // + // A host that is not in the table at all. Two playtest machines died + // here on the same instruction - the podium was up, a peer had left, + // and a drop zone assignment dispatched to a host GetRemoteHost had + // no row for, so GetConnectStatus read offset 0x24 off a NULL. The + // table's rows never leave it (disconnect only marks a host offline), + // so an absent ID was never adopted: host -1 is the known case, the + // ownerless map entities every log shows as 'Entity -1:106'. Whatever + // the ID's provenance, a message to a host that does not exist gets + // the same answer as one to a host that is offline - dropped - and + // the log names the ID so the next occurrence explains itself. + // + if (base_host == NULL) + { + static int said = 0; + + if (said < 8) + { + ++said; + DEBUG_STREAM << "Send: no host " << host_ID + << " in the table (client " << (int) client + << ", message " << message->messageID + << ") - dropped, not crashed\n" << std::flush; + } + CLEAR_SEND_PACKET(); + return; + } l4host = Cast_Object(L4Host*, base_host); if(l4host->GetConnectStatus() != L4Host::OnLineConnectionStatus) { @@ -1329,6 +1357,16 @@ Logical L4NetworkManager::SendMessageToNetnub( Check(host_manager); receiving_host = Cast_Object(L4Host*, host_manager->GetRemoteHost(host_ID)); + + // + // Same guard as Send, one layer down: an ID with no row in the table + // answers True - message consumed, nothing to retry - exactly like a + // host that is offline. + // + if (receiving_host == NULL) + { + return True; + } if (receiving_host->GetConnectStatus() != L4Host::OnLineConnectionStatus) { return True; diff --git a/MUNGA_L4/L4STEAMTRANSPORT.cpp b/MUNGA_L4/L4STEAMTRANSPORT.cpp index 77bb641..bf0b5e3 100644 --- a/MUNGA_L4/L4STEAMTRANSPORT.cpp +++ b/MUNGA_L4/L4STEAMTRANSPORT.cpp @@ -395,10 +395,30 @@ namespace // render loop yet at this point - this runs before the engine // block - so nothing else is keeping it alive. // + // + // The deadline is PER ATTEMPT, and attempts are capped, rather + // than one budget across all attempts. + // + // The 2026-08-11 playtest showed why, on every machine that met + // the one badly-NATed peer: the first attempt goes for a direct + // path, burns around ten seconds, and dies with 'timed out + // attempting to connect' (5003) or 'negotiate rendezvous' + // (5008); the SECOND attempt comes up through Valve's relay and + // succeeds - whenever it is given time. Under one shared budget + // the relay attempt inherited whatever the direct attempt left, + // and the logs show it being cut off mid-connect ('attempt 2 + // ended in state 1' - still connecting) at the 20s mark. Races + // then could not assemble, because the mesh needs every pair. + // + // Three attempts at RP412CONNECTWAIT each: the observed failure + // connects on attempt 2 at about half a minute, the truly + // unreachable peer costs about a minute instead of twenty + // seconds, and ESC still works throughout. + // DWORD wait_seconds = (DWORD) NetTransport_ConnectWaitSeconds(); DWORD started = GetTickCount(); - DWORD deadline = started + wait_seconds * 1000; int attempt = 0; + const int kMaxAttempts = 3; char progress[256]; sprintf( @@ -411,6 +431,7 @@ namespace for (;;) { ++attempt; + DWORD deadline = GetTickCount() + wait_seconds * 1000; HSteamNetConnection handle = SteamNetworkingSockets()->ConnectByIPAddress(target, 0, NULL); if (handle == k_HSteamNetConnection_Invalid) @@ -455,8 +476,9 @@ namespace sprintf( progress, - "Red Planet - connecting to %s ... %us left, ESC to cancel", + "Red Planet - connecting to %s (try %d of %d) ... %us left, ESC to cancel", inet_ntoa(remote->sin_addr), + attempt, kMaxAttempts, (unsigned) left ); NetTransport_SetWaitProgress(progress); @@ -487,15 +509,18 @@ namespace return (Connection) handle; } - // attempt failed - drop it and retry until the deadline + // attempt failed - drop it and retry with a fresh window DEBUG_STREAM << "SteamNetTransport: attempt " << attempt << " ended in state " << (int) state << "\n" << std::flush; SteamNetworkingSockets()->CloseConnection(handle, 0, "retry", false); RemoveConnection(handle); - if ((LONG)(GetTickCount() - deadline) >= 0) + if (attempt >= kMaxAttempts) { - DEBUG_STREAM << "SteamNetTransport: connect timed out after " - << wait_seconds << "s (RP412CONNECTWAIT)\n" << std::flush; + DEBUG_STREAM << "SteamNetTransport: gave up after " + << attempt << " attempts of " << wait_seconds + << "s each (RP412CONNECTWAIT), " + << ((GetTickCount() - started) / 1000) + << "s in all\n" << std::flush; NetTransport_SetWaitProgress(NULL); return InvalidConnection; } diff --git a/RP_L4/RPL4ENVIRON.cpp b/RP_L4/RPL4ENVIRON.cpp index 61c0ce2..9f39c2f 100644 --- a/RP_L4/RPL4ENVIRON.cpp +++ b/RP_L4/RPL4ENVIRON.cpp @@ -321,20 +321,20 @@ namespace "# the old arrival-time behaviour if you want to compare.\n" "#RP412NETCLOCK=0\n" "\n" -"# How long to keep redialling a player who has not answered yet, in\n" -"# seconds. 2 to 300, default 20.\n" +"# How long each connection attempt to another machine may take, in\n" +"# seconds. 2 to 300, default 20, and up to three attempts are made.\n" "#\n" -"# Launching a race connects to each machine in turn, and retries while\n" -"# one is not listening yet, because they finish loading at different\n" -"# moments. The wait used to be two minutes, which suited the arcade: a\n" -"# pod that was still booting would always answer eventually, on a LAN\n" -"# with nothing else to go wrong. Over the internet a machine that has\n" -"# been silent for twenty seconds is not coming - it never launched, or\n" -"# something between you cannot be crossed - so the default is twenty.\n" +"# Per attempt matters. Steam tries a direct path first, and behind some\n" +"# routers that burns ten seconds and fails; the second attempt comes up\n" +"# through Valve's relay and succeeds - if it is given time. The first\n" +"# playtest with six players showed a shared budget cutting that second\n" +"# attempt off mid-connect, and races could not assemble because the\n" +"# mesh needs every machine to reach every other. Three attempts of\n" +"# twenty seconds each connects the awkward router in about half a\n" +"# minute, and gives up on a truly unreachable one inside a minute.\n" "#\n" -"# The window stays alive throughout and the title bar counts down, and\n" -"# ESC gives up immediately. Raise this if you play with someone whose\n" -"# machine loads very slowly.\n" +"# The window stays alive throughout, the title bar names the peer and\n" +"# counts down each attempt, and ESC gives up immediately.\n" "RP412CONNECTWAIT=20\n" "\n" "# How much memory to set aside for a recording, in megabytes. 1 to 512,\n" diff --git a/playtestlogs/20260811/message.txt b/playtestlogs/20260811/message.txt new file mode 100644 index 0000000..4ed2a90 --- /dev/null +++ b/playtestlogs/20260811/message.txt @@ -0,0 +1,154 @@ +Red Planet 4.12.217 (056ee0b) +Environ: 12 setting(s) from environ.ini +Environ: environ.ini does not mention 24 option(s) this build knows: RP412INPUTFOCUS, L4MAPPOS, L4MAPSCALE, RP412PODIUMHOLD, RP412PHYSICSHZ, RP412INTERP, RP412NETPREDICT, RP412GAUGESLICE, RP412MAPRATE, RP412GAUGEDIAG, RP412LAMPSWEEP, RP412CONNECTWAIT, RP412RECORDSIZE, RP412GAUGEPROFILE, RP412RENDERDIAG, RP412PHYSTRACE, RP412SPAWNZONE, RP412INPUTSCRIPT, RP412JOYLOG, RP412AUDIOVOLUME, RP412AUDIOBASS, RP412VERTEXPROC, RP412VSYNC, RP412CAMLOG +Environ: they are at their built-in defaults - delete environ.ini to get the documented file back +L4CONTROLS=PAD;KEYBOARD +Video: frame target 60 fps, drawing interpolated across the physics step +SteamNetTransport: up as 169.254.8.177 (fake ports 33416 console, 33417 game) +L4Application: -fit chose -res 1920 1080 (100% canvas) for the 2560x1080 monitor +L4Application: -fit placed the window borderless at 2560x1080 before the first mission +FrontEnd: callsign "Pilot" and loadout from pilot.cfg +FrontEnd: saved callsign "PoorImpulseControl" and loadout to pilot.cfg +Lobby: joined 109775241819393971 +SteamNetTransport: peer registered: 169.254.88.186 (console 10608, game 10609, id 76561198659597127) +SteamNetTransport: peer registered: 169.254.35.214 (console 62256, game 62257, id 76561197995508393) +SteamNetTransport: peer registered: 169.254.105.170 (console 4648, game 4649, id 76561197970536135) +SteamNetTransport: peer registered: 169.254.240.193 (console 7168, game 7169, id 76561197976435895) +SteamNetTransport: peer registered: 169.254.8.177 (console 33416, game 33417, id 76561197969401853) +SteamNetTransport: peer registered: 169.254.122.50 (console 41360, game 41361, id 76561198022091594) +PadBindings: 59 key buttons, 8 key axes, 10 pad buttons, 5 pad axes +PadRIO: virtual RIO active (XInput pad + keyboard) +PadRIO: controls answer only while the game window has focus +Trying to find the monitor marked as active in Windows... +Monitor 0 was set as active in Windows... setting it as the primary monitor. +Either MFDs are explicitly disabled, we're running in windowed mode, or we don't have enough monitors attached to this machine. MFD monitors will not be detected. +Game is currently running windowed mode- will set all remaining undefined monitors to be the same as the primary monitor. +Video: presentation interval vsync +Video: vertex processing HARDWARE +SVGA16: cockpit canvas at 100% for the 2560x1080 work area +SVGA16: secondary displays at UL 100% UC 100% UR 100% LL 100% LR 100% radar 100% +SVGA16: radar on the bottom centre (L4RADARPOS) +SVGA16: cockpit fitted 1920x1080 at 100% in a 2560x1080 client +GaugeInterpreter: undefined label 'Initialization' +SteamNetTransport: listening on engine port 1501 (fake port 33416)... +PadRIO: controller 0 connected +SteamNetTransport: incoming [#4027028733 P2P steamid:76561198659597127@169.254.248.212:15404 fakeport #0] - accepting +SteamNetTransport: connected [#4027028733 P2P SDR steamid:76561198659597127@169.254.248.212:15404 fakeport #0] +STATUS: socket accepted from 169.254.88.186:1501! +Connected to ConsoleHost at 169.254.88.186:1501 +SteamNetTransport: connecting to 169.254.88.186:1502 (fake port 10609)... +SteamNetTransport: connected [#2546421614 P2P SDR steamid:76561198659597127@169.254.88.186:10609] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.35.214:1502 (fake port 62257)... +SteamNetTransport: connected [#3892042932 P2P SDR steamid:76561197995508393@169.254.35.214:62257] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.105.170:1502 (fake port 4649)... +SteamNetTransport: dropped [#1183141278 P2P ?@169.254.105.170:4649] end reason 5003: Timed out attempting to connect +SteamNetTransport: attempt 1 ended in state 5 +SteamNetTransport: attempt 2 ended in state 1 +SteamNetTransport: connect timed out after 20s (RP412CONNECTWAIT) +Could not open connection to 169.254.105.170:1502. +SteamNetTransport: connecting to 169.254.240.193:1502 (fake port 7169)... +SteamNetTransport: connected [#555564226 P2P SDR steamid:76561197976435895@169.254.240.193:7169] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: listening on engine port 1502 (fake port 33417)... +Connected to GameMachineHost at 169.254.88.186:1502 +Connected to GameMachineHost at 169.254.35.214:1502 +Connected to GameMachineHost at 169.254.240.193:1502 +SteamNetTransport: connecting to 169.254.88.186:1502 (fake port 10609)... +SteamNetTransport: incoming [#1946318435 P2P steamid:76561198022091594@169.254.251.68:21949 fakeport #1] - accepting +SteamNetTransport: connected [#1380037914 P2P SDR steamid:76561198659597127@169.254.88.186:10609] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.35.214:1502 (fake port 62257)... +SteamNetTransport: connected [#1946318435 P2P SDR steamid:76561198022091594@169.254.251.68:21949 fakeport #1] +SteamNetTransport: connected [#371675616 P2P SDR steamid:76561197995508393@169.254.35.214:62257] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.105.170:1502 (fake port 4649)... +SteamNetTransport: dropped [#1416324186 P2P ?@169.254.105.170:4649] end reason 5003: Timed out attempting to connect +SteamNetTransport: attempt 1 ended in state 5 +SteamNetTransport: connected [#2299564679 P2P SDR steamid:76561197970536135@169.254.105.170:4649] +SteamNetTransport: connect succeeded (attempt 2) +SteamNetTransport: connecting to 169.254.240.193:1502 (fake port 7169)... +SteamNetTransport: connected [#1693276213 P2P SDR steamid:76561197976435895@169.254.240.193:7169] +SteamNetTransport: connect succeeded (attempt 1) +Listen requested on port 1502 but gameListenerSocket already existed! +STATUS: socket accepted from 169.254.122.50:1502! +Connected to GameMachineHost at 169.254.122.50:1502 +Connected to GameMachineHost at 169.254.88.186:1502 +Connected to GameMachineHost at 169.254.35.214:1502 +Connected to GameMachineHost at 169.254.105.170:1502 +Connected to GameMachineHost at 169.254.240.193:1502 +All connections completed! +SteamNetTransport: connecting to 169.254.88.186:1502 (fake port 10609)... +SteamNetTransport: incoming [#418395659 P2P steamid:76561198022091594@169.254.251.68:21949 fakeport #1] - accepting +SteamNetTransport: connected [#3771470973 P2P SDR steamid:76561198659597127@169.254.88.186:10609] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.35.214:1502 (fake port 62257)... +SteamNetTransport: connected [#418395659 P2P SDR steamid:76561198022091594@169.254.251.68:21949 fakeport #1] +SteamNetTransport: connected [#107458131 P2P SDR steamid:76561197995508393@169.254.35.214:62257] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.105.170:1502 (fake port 4649)... +SteamNetTransport: connected [#173068106 P2P SDR steamid:76561197970536135@169.254.105.170:4649] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.240.193:1502 (fake port 7169)... +SteamNetTransport: connected [#1962487129 P2P SDR steamid:76561197976435895@169.254.240.193:7169] +SteamNetTransport: connect succeeded (attempt 1) +Listen requested on port 1502 but gameListenerSocket already existed! +STATUS: socket accepted from 169.254.122.50:1502! +Connected to GameMachineHost at 169.254.122.50:1502 +Connected to GameMachineHost at 169.254.88.186:1502 +Connected to GameMachineHost at 169.254.35.214:1502 +Connected to GameMachineHost at 169.254.105.170:1502 +Connected to GameMachineHost at 169.254.240.193:1502 +All connections completed! +SteamNetTransport: connecting to 169.254.88.186:1502 (fake port 10609)... +SteamNetTransport: connected [#3345733046 P2P SDR steamid:76561198659597127@169.254.88.186:10609] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.35.214:1502 (fake port 62257)... +SteamNetTransport: connected [#488432965 P2P SDR steamid:76561197995508393@169.254.35.214:62257] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.105.170:1502 (fake port 4649)... +SteamNetTransport: incoming [#1418378592 P2P steamid:76561198022091594@169.254.251.68:21949 fakeport #1] - accepting +SteamNetTransport: connected [#1418378592 P2P SDR steamid:76561198022091594@169.254.251.68:21949 fakeport #1] +SteamNetTransport: dropped [#1982903022 P2P steamid:76561197970536135@169.254.105.170:4649] end reason 5003: Timed out attempting to connect +SteamNetTransport: attempt 1 ended in state 5 +SteamNetTransport: attempt 2 ended in state 1 +SteamNetTransport: connect timed out after 20s (RP412CONNECTWAIT) +Could not open connection to 169.254.105.170:1502. +SteamNetTransport: connecting to 169.254.240.193:1502 (fake port 7169)... +SteamNetTransport: connected [#3943096642 P2P SDR steamid:76561197976435895@169.254.240.193:7169] +SteamNetTransport: connect succeeded (attempt 1) +Listen requested on port 1502 but gameListenerSocket already existed! +STATUS: socket accepted from 169.254.122.50:1502! +Connected to GameMachineHost at 169.254.122.50:1502 +Connected to GameMachineHost at 169.254.88.186:1502 +Connected to GameMachineHost at 169.254.35.214:1502 +Connected to GameMachineHost at 169.254.240.193:1502 +SteamNetTransport: connecting to 169.254.88.186:1502 (fake port 10609)... +SteamNetTransport: connected [#1251939970 P2P SDR steamid:76561198659597127@169.254.88.186:10609] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.35.214:1502 (fake port 62257)... +SteamNetTransport: connected [#389222490 P2P SDR steamid:76561197995508393@169.254.35.214:62257] +SteamNetTransport: connect succeeded (attempt 1) +SteamNetTransport: connecting to 169.254.105.170:1502 (fake port 4649)... +SteamNetTransport: incoming [#2399032524 P2P steamid:76561198022091594@169.254.251.68:21949 fakeport #1] - accepting +SteamNetTransport: connected [#2399032524 P2P SDR steamid:76561198022091594@169.254.251.68:21949 fakeport #1] +SteamNetTransport: dropped [#3050802723 P2P steamid:76561197970536135@169.254.105.170:4649] end reason 5003: Timed out attempting to connect +SteamNetTransport: attempt 1 ended in state 5 +SteamNetTransport: connected [#4019172527 P2P SDR steamid:76561197970536135@169.254.105.170:4649] +SteamNetTransport: connect succeeded (attempt 2) +SteamNetTransport: connecting to 169.254.240.193:1502 (fake port 7169)... +SteamNetTransport: connected [#2022716960 P2P SDR steamid:76561197976435895@169.254.240.193:7169] +SteamNetTransport: connect succeeded (attempt 1) +Listen requested on port 1502 but gameListenerSocket already existed! +STATUS: socket accepted from 169.254.122.50:1502! +Connected to GameMachineHost at 169.254.122.50:1502 +Connected to GameMachineHost at 169.254.88.186:1502 +Connected to GameMachineHost at 169.254.35.214:1502 +Connected to GameMachineHost at 169.254.105.170:1502 +Connected to GameMachineHost at 169.254.240.193:1502 +All connections completed! +NetClock: host 2 first sample, offset -51745 ms +NetClock: host 3 first sample, offset -16521 ms +NetClock: host 4 first sample, offset 20923 ms +Physics: fixed step, 50 Hz \ No newline at end of file diff --git a/playtestlogs/20260811/rpl4crash (1).dmp b/playtestlogs/20260811/rpl4crash (1).dmp new file mode 100644 index 0000000..0d07695 Binary files /dev/null and b/playtestlogs/20260811/rpl4crash (1).dmp differ diff --git a/playtestlogs/20260811/rpl4crash (2).dmp b/playtestlogs/20260811/rpl4crash (2).dmp new file mode 100644 index 0000000..1de0064 Binary files /dev/null and b/playtestlogs/20260811/rpl4crash (2).dmp differ diff --git a/playtestlogs/20260811/rpl4crash (3).dmp b/playtestlogs/20260811/rpl4crash (3).dmp new file mode 100644 index 0000000..a3430cd Binary files /dev/null and b/playtestlogs/20260811/rpl4crash (3).dmp differ