From c3571c876e5504062e43e710af72b8218b681aa2 Mon Sep 17 00:00:00 2001 From: k0 <21180271+k073l@users.noreply.github.com> Date: Mon, 1 Jun 2026 16:16:25 +0200 Subject: [PATCH 1/3] fix(saveables): switch to onLoadComplete flag lock --- .../Patches/GenericSaveables.Patches.cs | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/S1API/Internal/Patches/GenericSaveables.Patches.cs b/S1API/Internal/Patches/GenericSaveables.Patches.cs index f7b98ed..7853dcb 100644 --- a/S1API/Internal/Patches/GenericSaveables.Patches.cs +++ b/S1API/Internal/Patches/GenericSaveables.Patches.cs @@ -1,6 +1,7 @@ using System; using System.IO; using HarmonyLib; +using MelonLoader; using Newtonsoft.Json; using S1API.Internal.Abstraction; using S1API.Saveables; @@ -71,7 +72,7 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) } } - private static string lastLoadedGameFolderPath = null; + private static bool sameSession = false; /// /// Loads saveables marked with BeforeBaseGame load order BEFORE base game loaders run. @@ -89,12 +90,9 @@ private static void BeforeBaseLoaders(S1Persistence.LoadRequest request) if (lm == null || string.IsNullOrEmpty(lm.LoadedGameFolderPath)) return; - // Only run once per load cycle by checking if the folder path has changed - if (lastLoadedGameFolderPath == lm.LoadedGameFolderPath) - return; - - lastLoadedGameFolderPath = lm.LoadedGameFolderPath; - + // QueueLoadRequest may be called multiple times before loading into a save + // this flag makes sure we only load once - it's cleared by onLoadComplete + if (sameSession) return; string basePath = Path.Combine(lm.LoadedGameFolderPath, "Modded", "Saveables"); foreach (var saveable in SaveableAutoRegistry.GetRegisteredSaveables()) @@ -129,6 +127,23 @@ void InitializeOnLoadComplete() EventHelper.AddListener(InitializeOnLoadComplete, lm.onLoadComplete); } } + + // Lock subsequent calls to this prefix until load completes to avoid loading multiple times in the same session + sameSession = true; + // Clear the lock once the game is loaded to allow loading again in future sessions without restarting the game + void ClearLockOnLoadComplete() + { + try + { + EventHelper.RemoveListener(ClearLockOnLoadComplete, lm.onLoadComplete); + sameSession = false; + } + catch (Exception e) + { + try { MelonLoader.MelonLogger.Warning($"[Saveables] ClearLockOnLoadComplete failed: {e.Message}\n{e.StackTrace}"); } catch { } + } + } + EventHelper.AddListener(ClearLockOnLoadComplete, lm.onLoadComplete); } catch (Exception e) { From 85172408410b4149d287ed5ca513bd30c9277eee Mon Sep 17 00:00:00 2001 From: k0 <21180271+k073l@users.noreply.github.com> Date: Mon, 1 Jun 2026 16:46:20 +0200 Subject: [PATCH 2/3] fix(saveables): update docstring, remove ML import --- S1API/Internal/Patches/GenericSaveables.Patches.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/S1API/Internal/Patches/GenericSaveables.Patches.cs b/S1API/Internal/Patches/GenericSaveables.Patches.cs index 7853dcb..cdd4454 100644 --- a/S1API/Internal/Patches/GenericSaveables.Patches.cs +++ b/S1API/Internal/Patches/GenericSaveables.Patches.cs @@ -1,7 +1,6 @@ using System; using System.IO; using HarmonyLib; -using MelonLoader; using Newtonsoft.Json; using S1API.Internal.Abstraction; using S1API.Saveables; @@ -78,7 +77,7 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) /// Loads saveables marked with BeforeBaseGame load order BEFORE base game loaders run. /// This runs as a prefix to LoadManager.QueueLoadRequest on the first LoadRequest creation, /// which happens right before base game loaders start processing. - /// Uses the LoadedGameFolderPath to detect new load cycles. + /// Uses a session flag cleared by onLoadComplete to detect new load cycles. /// [HarmonyPatch(typeof(S1Persistence.LoadManager), nameof(S1Persistence.LoadManager.QueueLoadRequest))] [HarmonyPrefix] From 90a163b9ba6fec6617bad0880af344ddeb6f4fa0 Mon Sep 17 00:00:00 2001 From: ifBars Date: Wed, 3 Jun 2026 16:57:59 -0700 Subject: [PATCH 3/3] docs(saveables): clarify before-base load cycle detection --- S1API/Internal/Patches/GenericSaveables.Patches.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/S1API/Internal/Patches/GenericSaveables.Patches.cs b/S1API/Internal/Patches/GenericSaveables.Patches.cs index cdd4454..c972bd8 100644 --- a/S1API/Internal/Patches/GenericSaveables.Patches.cs +++ b/S1API/Internal/Patches/GenericSaveables.Patches.cs @@ -76,8 +76,9 @@ private static void SaveManager_Save_Postfix(string saveFolderPath) /// /// Loads saveables marked with BeforeBaseGame load order BEFORE base game loaders run. /// This runs as a prefix to LoadManager.QueueLoadRequest on the first LoadRequest creation, - /// which happens right before base game loaders start processing. - /// Uses a session flag cleared by onLoadComplete to detect new load cycles. + /// before base game loaders start processing. + /// Uses an internal sameSession flag to detect new load cycles. sameSession is reset by + /// onLoadComplete so subsequent load cycles can be detected. /// [HarmonyPatch(typeof(S1Persistence.LoadManager), nameof(S1Persistence.LoadManager.QueueLoadRequest))] [HarmonyPrefix]