From 09c85e3d960a2935ccf7a6ba922257b58125640b Mon Sep 17 00:00:00 2001 From: MrMaho Date: Sun, 27 Sep 2026 17:31:47 +0200 Subject: [PATCH] Keep kick reason and reconnect intent across MSCLoader's mod reload on returning to the menu Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 ++ MultiplayerManager.cs | 76 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2078430..41ad283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ Server und Mod müssen beide 2.8 sein (Server: `git pull && docker compose up -d Nach Kick, Ban oder eigenem Trennen wird nicht neu verbunden **Behoben** +- Nach Kick/Reset kam weder das Fenster mit dem Grund noch das automatische Neu-Verbinden: MSCLoader lädt beim Wechsel + ins Hauptmenü alle Mods neu und damit ging der Zustand verloren. Er wird jetzt vorher gesichert und danach fortgesetzt - Absturz („NaN … collider“) und abfallende Teile am Satsuma: Türen/Haube/Kofferraum wurden gegen das Scharnier an ihre Position teleportiert – das erzeugte riesige Kräfte. Jetzt zieht die Feder des Scharniers sie sanft auf den Winkel - Beim anderen Spieler „orgelte“ der Anlasser endlos: erzwungene Geräusche/Lichter werden losgelassen, sobald keine diff --git a/MultiplayerManager.cs b/MultiplayerManager.cs index 44d3518..992cb1b 100644 --- a/MultiplayerManager.cs +++ b/MultiplayerManager.cs @@ -128,6 +128,7 @@ namespace MSCO }; FsmSync.Init(); SafetyPatches.Apply(); // verhindert den Absturz durch Kreis in der Objekt-Hierarchie + RestorePendingState(); discord.Start(); steam.Created += OnSteamLobbyCreated; @@ -833,6 +834,7 @@ namespace MSCO menuButtonsHidden = MenuHelper.HideGameMenuButtons() > 0; } UpdateOverlayKeys(); + PersistPendingState(); // Kick-Grund / Neu-Verbinden über das Neuladen der Mods hinweg merken MscoLog.Drain(overlays.Log); // alle Mod-Meldungen in die MSCO-Konsole (F7) UpdatePresence(); @@ -939,6 +941,79 @@ namespace MSCO /// Warum man zuletzt getrennt wurde - wird im Hauptmenü angezeigt, bis man OK drückt. public string DisconnectNotice { get; private set; } + + // ---------------------------------------------------------------- Über Neuladen hinweg merken + // Beim Wechsel ins Hauptmenü lädt MSCLoader alle Mods neu - dabei ginge der Kick-Grund bzw. "bitte neu + // verbinden" verloren, bevor man das Menü überhaupt sieht. Deshalb in den PlayerPrefs sichern. + const string PrefNotice = "MSCO_PendingNotice"; + const string PrefReconnect = "MSCO_PendingReconnect"; + const double NoticeMaxAgeMinutes = 10; + const double ReconnectMaxAgeMinutes = 3; + string savedNotice, savedReconnect; + int savedAttempts = -1; + + void PersistPendingState() + { + if (ReferenceEquals(savedNotice, DisconnectNotice) && ReferenceEquals(savedReconnect, reconnectMessage) + && savedAttempts == reconnectAttempts) return; + savedNotice = DisconnectNotice; + savedReconnect = reconnectMessage; + savedAttempts = reconnectAttempts; + string now = System.DateTime.UtcNow.Ticks.ToString(); + try + { + if (DisconnectNotice != null) PlayerPrefs.SetString(PrefNotice, now + "\n" + DisconnectNotice); + else PlayerPrefs.DeleteKey(PrefNotice); + if (reconnectMessage != null && lastServerHost != null) + PlayerPrefs.SetString(PrefReconnect, string.Join("\n", new[] + { + now, lastServerHost, lastServerPort.ToString(), lastServerName ?? "", lastServerMax.ToString(), + reconnectAttempts.ToString(), reconnectMessage + })); + else PlayerPrefs.DeleteKey(PrefReconnect); + PlayerPrefs.Save(); + } + catch (System.Exception e) { MscoLog.Warning("Could not remember the disconnect state: " + e.Message); } + } + + static bool Fresh(string ticks, double maxMinutes) + { + long t; + return long.TryParse(ticks, out t) && (System.DateTime.UtcNow - new System.DateTime(t)).TotalMinutes < maxMinutes; + } + + void RestorePendingState() + { + try + { + string[] notice = PlayerPrefs.GetString(PrefNotice, "").Split(new[] { '\n' }, 2); + if (notice.Length == 2 && Fresh(notice[0], NoticeMaxAgeMinutes)) DisconnectNotice = notice[1]; + + string[] rc = PlayerPrefs.GetString(PrefReconnect, "").Split(new[] { '\n' }, 7); + int port, max, attempts; + if (rc.Length == 7 && Fresh(rc[0], ReconnectMaxAgeMinutes) && int.TryParse(rc[2], out port) + && int.TryParse(rc[4], out max) && int.TryParse(rc[5], out attempts)) + { + lastServerHost = rc[1]; + lastServerPort = port; + lastServerName = rc[3].Length > 0 ? rc[3] : null; + lastServerMax = max; + reconnectAttempts = attempts; + reconnectMessage = rc[6]; + reconnectAt = Time.realtimeSinceStartup + 2f; // erst das Menü fertig laden lassen + DisconnectNotice = null; + MscoLog.Info("[MSCO] Continuing reconnect to " + lastServerHost + ":" + lastServerPort); + } + } + catch (System.Exception e) { MscoLog.Warning("Could not restore the disconnect state: " + e.Message); } + savedNotice = DisconnectNotice; + savedReconnect = reconnectMessage; + savedAttempts = reconnectAttempts; + // Einmal gelesen = erledigt; neu gespeichert wird bei der nächsten Änderung + PlayerPrefs.DeleteKey(PrefNotice); + PlayerPrefs.DeleteKey(PrefReconnect); + if (DisconnectNotice != null || reconnectMessage != null) { savedNotice = null; savedReconnect = null; savedAttempts = -1; } + } public void ClearDisconnectNotice() { DisconnectNotice = null; } public bool IsReconnecting { get { return reconnectMessage != null && session == null; } } public int ReconnectAttempt { get { return reconnectAttempts; } } @@ -1057,6 +1132,7 @@ namespace MSCO if (wasClientInGame) { SetStatus("Disconnected from host: " + reason); + PersistPendingState(); // MSCLoader lädt die Mods im Menü neu - vorher sichern Application.LoadLevel(MenuHelper.MenuScene); } }