fix save folder constants not available during early load stages

This commit is contained in:
Jesse Plamondon-Willard 2019-02-07 22:28:55 -05:00
parent 79c6166005
commit 9240bdbf9b
No known key found for this signature in database
GPG Key ID: 7D7C8097B62033CE
4 changed files with 79 additions and 29 deletions

View File

@ -1,4 +1,9 @@
# Release notes
## Upcoming
* For modders:
* Fixed `Constants.SaveFolderName` and `CurrentSavePath` not available during early load stages when using `Specialised.LoadStageChanged` event.
## 2.10.1
Released 30 December 2018 for Stardew Valley 1.3.32.

View File

@ -2,6 +2,7 @@ using System;
using System.IO;
using System.Linq;
using System.Reflection;
using StardewModdingAPI.Enums;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.ModLoading;
using StardewModdingAPI.Internal;
@ -12,16 +13,6 @@ namespace StardewModdingAPI
/// <summary>Contains SMAPI's constants and assumptions.</summary>
public static class Constants
{
/*********
** Fields
*********/
/// <summary>The directory path containing the current save's data (if a save is loaded).</summary>
private static string RawSavePath => Context.IsSaveLoaded ? Path.Combine(Constants.SavesPath, Constants.GetSaveFolderName()) : null;
/// <summary>Whether the directory containing the current save's data exists on disk.</summary>
private static bool SavePathReady => Context.IsSaveLoaded && Directory.Exists(Constants.RawSavePath);
/*********
** Accessors
*********/
@ -52,11 +43,33 @@ namespace StardewModdingAPI
/// <summary>The directory path where all saves are stored.</summary>
public static string SavesPath { get; } = Path.Combine(Constants.DataPath, "Saves");
/// <summary>The directory name containing the current save's data (if a save is loaded and the directory exists).</summary>
public static string SaveFolderName => Context.IsSaveLoaded ? Constants.GetSaveFolderName() : "";
/// <summary>The name of the current save folder (if save info is available, regardless of whether the save file exists yet).</summary>
public static string SaveFolderName
{
get
{
return Constants.GetSaveFolderName()
#if SMAPI_3_0_STRICT
;
#else
?? "";
#endif
}
}
/// <summary>The directory path containing the current save's data (if a save is loaded and the directory exists).</summary>
public static string CurrentSavePath => Constants.SavePathReady ? Path.Combine(Constants.SavesPath, Constants.GetSaveFolderName()) : "";
/// <summary>The absolute path to the current save folder (if save info is available and the save file exists).</summary>
public static string CurrentSavePath
{
get
{
return Constants.GetSaveFolderPathIfExists()
#if SMAPI_3_0_STRICT
;
#else
?? "";
#endif
}
}
/****
** Internal
@ -184,13 +197,6 @@ namespace StardewModdingAPI
/*********
** Private methods
*********/
/// <summary>Get the name of a save directory for the current player.</summary>
private static string GetSaveFolderName()
{
string prefix = new string(Game1.player.Name.Where(char.IsLetterOrDigit).ToArray());
return $"{prefix}_{Game1.uniqueIDForThisGame}";
}
/// <summary>Get the game's current version string.</summary>
private static string GetGameVersion()
{
@ -200,5 +206,43 @@ namespace StardewModdingAPI
throw new InvalidOperationException($"The {nameof(Game1)}.{nameof(Game1.version)} field could not be found.");
return (string)field.GetValue(null);
}
/// <summary>Get the name of the save folder, if any.</summary>
internal static string GetSaveFolderName()
{
// save not available
if (Context.LoadStage == LoadStage.None)
return null;
// get basic info
string playerName;
ulong saveID;
if (Context.LoadStage == LoadStage.SaveParsed)
{
playerName = SaveGame.loaded.player.Name;
saveID = SaveGame.loaded.uniqueIDForThisGame;
}
else
{
playerName = Game1.player.Name;
saveID = Game1.uniqueIDForThisGame;
}
// build folder name
return $"{new string(playerName.Where(char.IsLetterOrDigit).ToArray())}_{saveID}";
}
/// <summary>Get the path to the current save folder, if any.</summary>
internal static string GetSaveFolderPathIfExists()
{
string folderName = Constants.GetSaveFolderName();
if (folderName == null)
return null;
string path = Path.Combine(Constants.SavesPath, folderName);
return Directory.Exists(path)
? path
: null;
}
}
}

View File

@ -1,3 +1,4 @@
using StardewModdingAPI.Enums;
using StardewModdingAPI.Events;
using StardewValley;
using StardewValley.Menus;
@ -39,5 +40,8 @@ namespace StardewModdingAPI
/// <summary>Whether the game is currently writing to the save file.</summary>
internal static bool IsSaving => Game1.activeClickableMenu is SaveGameMenu || Game1.activeClickableMenu is ShippingMenu; // saving is performed by SaveGameMenu, but it's wrapped by ShippingMenu on days when the player shipping something
/// <summary>The current stage in the game's loading process.</summary>
internal static LoadStage LoadStage { get; set; }
}
}

View File

@ -69,9 +69,6 @@ namespace StardewModdingAPI.Framework
/// <remarks>Skipping a few frames ensures the game finishes initialising the world before mods try to change it.</remarks>
private readonly Countdown AfterLoadTimer = new Countdown(5);
/// <summary>The current stage in the game's loading process.</summary>
private LoadStage LoadStage = LoadStage.None;
/// <summary>Whether the game is saving and SMAPI has already raised <see cref="IGameLoopEvents.Saving"/>.</summary>
private bool IsBetweenSaveEvents;
@ -215,12 +212,12 @@ namespace StardewModdingAPI.Framework
internal void OnLoadStageChanged(LoadStage newStage)
{
// nothing to do
if (newStage == this.LoadStage)
if (newStage == Context.LoadStage)
return;
// update data
LoadStage oldStage = this.LoadStage;
this.LoadStage = newStage;
LoadStage oldStage = Context.LoadStage;
Context.LoadStage = newStage;
if (newStage == LoadStage.None)
{
this.Monitor.Log("Context: returned to title", LogLevel.Trace);
@ -511,7 +508,7 @@ namespace StardewModdingAPI.Framework
*********/
if (wasWorldReady && !Context.IsWorldReady)
this.OnLoadStageChanged(LoadStage.None);
else if (Context.IsWorldReady && this.LoadStage != LoadStage.Ready)
else if (Context.IsWorldReady && Context.LoadStage != LoadStage.Ready)
{
// print context
string context = $"Context: loaded saved game '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.";
@ -884,7 +881,7 @@ namespace StardewModdingAPI.Framework
events.GameLaunched.Raise(new GameLaunchedEventArgs());
// preloaded
if (Context.IsSaveLoaded && this.LoadStage != LoadStage.Loaded && this.LoadStage != LoadStage.Ready)
if (Context.IsSaveLoaded && Context.LoadStage != LoadStage.Loaded && Context.LoadStage != LoadStage.Ready)
this.OnLoadStageChanged(LoadStage.Loaded);
// update tick