summaryrefslogtreecommitdiff
path: root/src/SMAPI
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI')
-rw-r--r--src/SMAPI/Enums/LoadStage.cs6
-rw-r--r--src/SMAPI/Patches/LoadContextPatch.cs53
2 files changed, 54 insertions, 5 deletions
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
/// <summary>The game is creating a new save slot, and has initialized the basic save info.</summary>
CreatedBasicInfo,
+ /// <summary>The game is creating a new save slot, and has added the location instances but hasn't fully initialized them yet.</summary>
+ CreatedInitialLocations,
+
/// <summary>The game is creating a new save slot, and has initialized the in-game locations.</summary>
CreatedLocations,
@@ -21,6 +24,9 @@ namespace StardewModdingAPI.Enums
/// <summary>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 <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 36.</summary>
SaveLoadedBasicInfo,
+ /// <summary>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.</summary>
+ SaveAddedLocations,
+
/// <summary>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 <see cref="StardewValley.SaveGame.getLoadEnumerator"/> value 50.</summary>
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
/// <summary>A callback to invoke when the load stage changes.</summary>
private static Action<LoadStage> OnStageChanged;
+ /// <summary>Whether the game is running running the code in <see cref="Game1.loadForNewGame"/>.</summary>
+ 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;
}
+ /// <summary>Called before <see cref="Game1.AddModNPCs"/>.</summary>
+ /// <returns>Returns whether to execute the original method.</returns>
+ /// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
+ 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;
+ }
+
+ /// <summary>Called before <see cref="Game1.loadForNewGame"/>.</summary>
+ /// <returns>Returns whether to execute the original method.</returns>
+ /// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
+ private static bool Before_Game1_LoadForNewGame()
+ {
+ LoadContextPatch.IsInLoadForNewGame = true;
+ return true;
+ }
+
/// <summary>Called after <see cref="Game1.loadForNewGame"/>.</summary>
/// <remarks>This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments.</remarks>
private static void After_Game1_LoadForNewGame()
{
- bool creating =
- (Game1.currentMinigame is Intro) // creating save with intro
- || (Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField<bool>(menu, "transitioningCharacterCreationMenu").GetValue()); // creating save, skipped intro
+ LoadContextPatch.IsInLoadForNewGame = false;
- if (creating)
+ if (LoadContextPatch.IsCreating())
LoadContextPatch.OnStageChanged(LoadStage.CreatedLocations);
}
+
+ /// <summary>Get whether the save file is currently being created.</summary>
+ private static bool IsCreating()
+ {
+ return
+ (Game1.currentMinigame is Intro) // creating save with intro
+ || (Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField<bool>(menu, "transitioningCharacterCreationMenu").GetValue()); // creating save, skipped intro
+ }
}
}