From f2dd11fe3fbe8b31665ad25e6e58b0026c00098e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 10 May 2019 23:49:08 -0400 Subject: [PATCH] fix inconsistent LoadStage behavior when creating a new save --- docs/release-notes.md | 1 + src/SMAPI/Framework/SGame.cs | 2 +- src/SMAPI/Patches/LoadContextPatch.cs | 55 +++++++++------------------ 3 files changed, 19 insertions(+), 39 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index 14d1a8fa..e4024d07 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -25,6 +25,7 @@ These changes have not been released yet. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. * Updated to Json.NET 12.0.1. + * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. ## 2.11.3 Released 13 September 2019 for Stardew Valley 1.3.36. diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 2d43f8c4..1d4db834 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -774,7 +774,7 @@ namespace StardewModdingAPI.Framework } // preloaded - if (Context.IsSaveLoaded && Context.LoadStage != LoadStage.Loaded && Context.LoadStage != LoadStage.Ready) + if (Context.IsSaveLoaded && Context.LoadStage != LoadStage.Loaded && Context.LoadStage != LoadStage.Ready && Game1.dayOfMonth != 0) this.OnLoadStageChanged(LoadStage.Loaded); // update tick diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs index 3f86c9a9..93a059aa 100644 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -1,16 +1,15 @@ using System; -using System.Collections.ObjectModel; -using System.Collections.Specialized; using Harmony; using StardewModdingAPI.Enums; using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; using StardewValley; using StardewValley.Menus; +using StardewValley.Minigames; namespace StardewModdingAPI.Patches { - /// A Harmony patch for which notifies SMAPI for save creation load stages. + /// Harmony patches which notify SMAPI for save creation load stages. /// This patch hooks into , checks if TitleMenu.transitioningCharacterCreationMenu is true (which means the player is creating a new save file), then raises after the location list is cleared twice (the second clear happens right before locations are created), and when the method ends. internal class LoadContextPatch : IHarmonyPatch { @@ -23,12 +22,6 @@ namespace StardewModdingAPI.Patches /// A callback to invoke when the load stage changes. private static Action OnStageChanged; - /// Whether was called as part of save creation. - private static bool IsCreating; - - /// The number of times that has been cleared since started. - private static int TimesLocationsCleared; - /********* ** Accessors @@ -53,9 +46,15 @@ namespace StardewModdingAPI.Patches /// The Harmony instance. public void Apply(HarmonyInstance harmony) { + // detect CreatedBasicInfo + harmony.Patch( + original: AccessTools.Method(typeof(TitleMenu), nameof(TitleMenu.createdNewCharacter)), + prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_TitleMenu_CreatedNewCharacter)) + ); + + // detect CreatedLocations harmony.Patch( original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)), - prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_Game1_LoadForNewGame)), postfix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.After_Game1_LoadForNewGame)) ); } @@ -64,45 +63,25 @@ namespace StardewModdingAPI.Patches /********* ** Private methods *********/ - /// The method to call instead of . + /// Called before . /// Returns whether to execute the original method. /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - private static bool Before_Game1_LoadForNewGame() + private static bool Before_TitleMenu_CreatedNewCharacter() { - LoadContextPatch.IsCreating = Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue(); - LoadContextPatch.TimesLocationsCleared = 0; - if (LoadContextPatch.IsCreating) - { - // raise CreatedBasicInfo after locations are cleared twice - ObservableCollection locations = (ObservableCollection)Game1.locations; - locations.CollectionChanged += LoadContextPatch.OnLocationListChanged; - } - + LoadContextPatch.OnStageChanged(LoadStage.CreatedBasicInfo); return true; } - /// The method to call instead after . + /// Called after . /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. private static void After_Game1_LoadForNewGame() { - if (LoadContextPatch.IsCreating) - { - // clean up - ObservableCollection locations = (ObservableCollection)Game1.locations; - locations.CollectionChanged -= LoadContextPatch.OnLocationListChanged; + bool creating = + (Game1.currentMinigame is Intro) // creating save with intro + || (Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue()); // creating save, skipped intro - // raise stage changed + if (creating) LoadContextPatch.OnStageChanged(LoadStage.CreatedLocations); - } - } - - /// Raised when changes. - /// The event sender. - /// The event arguments. - private static void OnLocationListChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (++LoadContextPatch.TimesLocationsCleared == 2) - LoadContextPatch.OnStageChanged(LoadStage.CreatedBasicInfo); } } }