From 944c03737e7f7d7788f4321224a4e59a4f04717d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 28 Feb 2021 12:01:11 -0500 Subject: add load stages immediately after game adds initial locations --- src/SMAPI/Enums/LoadStage.cs | 6 ++++ src/SMAPI/Patches/LoadContextPatch.cs | 53 +++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/SMAPI/Enums/LoadStage.cs b/src/SMAPI/Enums/LoadStage.cs index 5c2b0412..aa95d201 100644 --- a/src/SMAPI/Enums/LoadStage.cs +++ b/src/SMAPI/Enums/LoadStage.cs @@ -9,6 +9,9 @@ namespace StardewModdingAPI.Enums /// The game is creating a new save slot, and has initialized the basic save info. CreatedBasicInfo, + /// The game is creating a new save slot, and has added the location instances but hasn't fully initialized them yet. + CreatedInitialLocations, + /// The game is creating a new save slot, and has initialized the in-game locations. CreatedLocations, @@ -21,6 +24,9 @@ namespace StardewModdingAPI.Enums /// The game is loading a save slot, and has applied the basic save info (including player data). Not applicable when connecting to a multiplayer host. Note that some basic info (like daily luck) is not initialized at this point. This is equivalent to value 36. SaveLoadedBasicInfo, + /// The game is loading a save slot and has added the location instances, but hasn't applied the data yet. Not applicable when connecting to a multiplayer host. + SaveAddedLocations, + /// The game is loading a save slot, and has applied the in-game location data. Not applicable when connecting to a multiplayer host. This is equivalent to value 50. SaveLoadedLocations, diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs index ceda061b..9fddcc50 100644 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -29,6 +29,9 @@ namespace StardewModdingAPI.Patches /// A callback to invoke when the load stage changes. private static Action OnStageChanged; + /// Whether the game is running running the code in . + private static bool IsInLoadForNewGame; + /********* ** Accessors @@ -62,9 +65,16 @@ namespace StardewModdingAPI.Patches prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_TitleMenu_CreatedNewCharacter)) ); - // detect CreatedLocations + // detect CreatedInitialLocations and SaveAddedLocations + harmony.Patch( + original: AccessTools.Method(typeof(Game1), nameof(Game1.AddModNPCs)), + prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_Game1_AddModNPCs)) + ); + + // detect CreatedLocations, and track IsInLoadForNewGame 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)) ); } @@ -82,16 +92,49 @@ namespace StardewModdingAPI.Patches return true; } + /// 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_AddModNPCs() + { + // When this method is called from Game1.loadForNewGame, it happens right after adding the vanilla + // locations but before initializing them. + if (LoadContextPatch.IsInLoadForNewGame) + { + LoadContextPatch.OnStageChanged(LoadContextPatch.IsCreating() + ? LoadStage.CreatedInitialLocations + : LoadStage.SaveAddedLocations + ); + } + + return true; + } + + /// 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() + { + LoadContextPatch.IsInLoadForNewGame = true; + return true; + } + /// 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() { - 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 + LoadContextPatch.IsInLoadForNewGame = false; - if (creating) + if (LoadContextPatch.IsCreating()) LoadContextPatch.OnStageChanged(LoadStage.CreatedLocations); } + + /// Get whether the save file is currently being created. + private static bool IsCreating() + { + return + (Game1.currentMinigame is Intro) // creating save with intro + || (Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue()); // creating save, skipped intro + } } } -- cgit