From 9240bdbf9b6b54d820cb01953ceea31f5e06598e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 7 Feb 2019 22:28:55 -0500 Subject: fix save folder constants not available during early load stages --- src/SMAPI/Constants.cs | 86 +++++++++++++++++++++++++++++++++----------- src/SMAPI/Context.cs | 4 +++ src/SMAPI/Framework/SGame.cs | 13 +++---- 3 files changed, 74 insertions(+), 29 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index a0ba67ab..dde8f2a0 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -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 /// Contains SMAPI's constants and assumptions. public static class Constants { - /********* - ** Fields - *********/ - /// The directory path containing the current save's data (if a save is loaded). - private static string RawSavePath => Context.IsSaveLoaded ? Path.Combine(Constants.SavesPath, Constants.GetSaveFolderName()) : null; - - /// Whether the directory containing the current save's data exists on disk. - private static bool SavePathReady => Context.IsSaveLoaded && Directory.Exists(Constants.RawSavePath); - - /********* ** Accessors *********/ @@ -52,11 +43,33 @@ namespace StardewModdingAPI /// The directory path where all saves are stored. public static string SavesPath { get; } = Path.Combine(Constants.DataPath, "Saves"); - /// The directory name containing the current save's data (if a save is loaded and the directory exists). - public static string SaveFolderName => Context.IsSaveLoaded ? Constants.GetSaveFolderName() : ""; + /// The name of the current save folder (if save info is available, regardless of whether the save file exists yet). + public static string SaveFolderName + { + get + { + return Constants.GetSaveFolderName() +#if SMAPI_3_0_STRICT + ; +#else + ?? ""; +#endif + } + } - /// The directory path containing the current save's data (if a save is loaded and the directory exists). - public static string CurrentSavePath => Constants.SavePathReady ? Path.Combine(Constants.SavesPath, Constants.GetSaveFolderName()) : ""; + /// The absolute path to the current save folder (if save info is available and the save file exists). + public static string CurrentSavePath + { + get + { + return Constants.GetSaveFolderPathIfExists() +#if SMAPI_3_0_STRICT + ; +#else + ?? ""; +#endif + } + } /**** ** Internal @@ -184,13 +197,6 @@ namespace StardewModdingAPI /********* ** Private methods *********/ - /// Get the name of a save directory for the current player. - private static string GetSaveFolderName() - { - string prefix = new string(Game1.player.Name.Where(char.IsLetterOrDigit).ToArray()); - return $"{prefix}_{Game1.uniqueIDForThisGame}"; - } - /// Get the game's current version string. 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); } + + /// Get the name of the save folder, if any. + 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}"; + } + + /// Get the path to the current save folder, if any. + 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; + } } } diff --git a/src/SMAPI/Context.cs b/src/SMAPI/Context.cs index cd1cf1c2..1cdef7f1 100644 --- a/src/SMAPI/Context.cs +++ b/src/SMAPI/Context.cs @@ -1,3 +1,4 @@ +using StardewModdingAPI.Enums; using StardewModdingAPI.Events; using StardewValley; using StardewValley.Menus; @@ -39,5 +40,8 @@ namespace StardewModdingAPI /// Whether the game is currently writing to the save file. 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 + + /// The current stage in the game's loading process. + internal static LoadStage LoadStage { get; set; } } } diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 25ffcabd..6aff6c01 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -69,9 +69,6 @@ namespace StardewModdingAPI.Framework /// Skipping a few frames ensures the game finishes initialising the world before mods try to change it. private readonly Countdown AfterLoadTimer = new Countdown(5); - /// The current stage in the game's loading process. - private LoadStage LoadStage = LoadStage.None; - /// Whether the game is saving and SMAPI has already raised . 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 -- cgit From d8dd4b4c18f571c6e8a7264f0168a69fd04bce70 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 7 Feb 2019 22:30:09 -0500 Subject: fix LoadStage.SaveParsed raised before save data available --- src/SMAPI/Framework/SGame.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 6aff6c01..a90e8264 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -290,6 +290,7 @@ namespace StardewModdingAPI.Framework // Run async tasks synchronously to avoid issues due to mod events triggering // concurrently with game code. + bool saveParsed = false; if (Game1.currentLoader != null) { this.Monitor.Log("Game loader synchronising...", LogLevel.Trace); @@ -298,7 +299,8 @@ namespace StardewModdingAPI.Framework // raise load stage changed switch (Game1.currentLoader.Current) { - case 20: + case 20 when (!saveParsed && SaveGame.loaded != null): + saveParsed = true; this.OnLoadStageChanged(LoadStage.SaveParsed); break; -- cgit From ce060f30e69744ef4129998473220bf011c89fee Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 7 Feb 2019 22:34:18 -0500 Subject: set max game version to avoid confusion when 1.3.35 releases --- src/SMAPI/Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index dde8f2a0..f8d1638e 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -26,7 +26,7 @@ namespace StardewModdingAPI public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.32"); /// The maximum supported version of Stardew Valley. - public static ISemanticVersion MaximumGameVersion { get; } = null; + public static ISemanticVersion MaximumGameVersion { get; } = new GameVersion("1.3.33"); /// The target game platform. public static GamePlatform TargetPlatform => (GamePlatform)Constants.Platform; -- cgit From e064be0c7b3440b31b616cec8c43946097fdad7d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 31 Dec 2018 14:10:25 -0500 Subject: fix 'unknown mod' deprecation warnings showing wrong stack trace --- src/SMAPI/Framework/DeprecationManager.cs | 4 ++-- src/SMAPI/Framework/DeprecationWarning.cs | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs index 76c2f616..8d836c8c 100644 --- a/src/SMAPI/Framework/DeprecationManager.cs +++ b/src/SMAPI/Framework/DeprecationManager.cs @@ -62,7 +62,7 @@ namespace StardewModdingAPI.Framework return; // queue warning - this.QueuedWarnings.Add(new DeprecationWarning(source, nounPhrase, version, severity)); + this.QueuedWarnings.Add(new DeprecationWarning(source, nounPhrase, version, severity, Environment.StackTrace)); } /// Print any queued messages. @@ -79,7 +79,7 @@ namespace StardewModdingAPI.Framework : $"{warning.ModName ?? "An unknown mod"} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version})."; #endif if (warning.ModName == null) - message += $"{Environment.NewLine}{Environment.StackTrace}"; + message += $"{Environment.NewLine}{warning.StackTrace}"; // log message switch (warning.Level) diff --git a/src/SMAPI/Framework/DeprecationWarning.cs b/src/SMAPI/Framework/DeprecationWarning.cs index 25415012..5201b06c 100644 --- a/src/SMAPI/Framework/DeprecationWarning.cs +++ b/src/SMAPI/Framework/DeprecationWarning.cs @@ -18,6 +18,9 @@ namespace StardewModdingAPI.Framework /// The deprecation level for the affected code. public DeprecationLevel Level { get; } + /// The stack trace when the deprecation warning was raised. + public string StackTrace { get; } + /********* ** Public methods @@ -27,12 +30,14 @@ namespace StardewModdingAPI.Framework /// A noun phrase describing what is deprecated. /// The SMAPI version which deprecated it. /// The deprecation level for the affected code. - public DeprecationWarning(string modName, string nounPhrase, string version, DeprecationLevel level) + /// The stack trace when the deprecation warning was raised. + public DeprecationWarning(string modName, string nounPhrase, string version, DeprecationLevel level, string stackTrace) { this.ModName = modName; this.NounPhrase = nounPhrase; this.Version = version; this.Level = level; + this.StackTrace = stackTrace; } } } -- cgit From c4a76df4b07e9b3378f51e00909e09424ba09654 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 31 Dec 2018 14:16:43 -0500 Subject: fix 'unknown mod' deprecation warnings showing stack trace in non-developer mode --- src/SMAPI/Framework/DeprecationManager.cs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs index 8d836c8c..fcdf722e 100644 --- a/src/SMAPI/Framework/DeprecationManager.cs +++ b/src/SMAPI/Framework/DeprecationManager.cs @@ -78,27 +78,40 @@ namespace StardewModdingAPI.Framework ? $"{warning.ModName ?? "An unknown mod"} uses deprecated code (legacy events are deprecated since SMAPI {warning.Version})." : $"{warning.ModName ?? "An unknown mod"} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version})."; #endif - if (warning.ModName == null) - message += $"{Environment.NewLine}{warning.StackTrace}"; - // log message + // get log level + LogLevel level; switch (warning.Level) { case DeprecationLevel.Notice: - this.Monitor.Log(message, LogLevel.Trace); + level = LogLevel.Trace; break; case DeprecationLevel.Info: - this.Monitor.Log(message, LogLevel.Debug); + level = LogLevel.Debug; break; case DeprecationLevel.PendingRemoval: - this.Monitor.Log(message, LogLevel.Warn); + level = LogLevel.Warn; break; default: throw new NotSupportedException($"Unknown deprecation level '{warning.Level}'."); } + + // log message + if (warning.ModName != null) + this.Monitor.Log(message, level); + else + { + if (level == LogLevel.Trace) + this.Monitor.Log($"{message}\n{warning.StackTrace}", level); + else + { + this.Monitor.Log(message, level); + this.Monitor.Log(warning.StackTrace); + } + } } this.QueuedWarnings.Clear(); } -- cgit From 0f926ca1c9d5d1323ddf10ceaa0ad4e9e7d02d3c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 31 Dec 2018 14:40:42 -0500 Subject: fix 'unknown mod' deprecation warnings when they occur in the Mod constructor --- src/SMAPI/Framework/ModRegistry.cs | 10 ++++++++-- src/SMAPI/Framework/SCore.cs | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ModRegistry.cs b/src/SMAPI/Framework/ModRegistry.cs index e9ceb66e..5be33cb4 100644 --- a/src/SMAPI/Framework/ModRegistry.cs +++ b/src/SMAPI/Framework/ModRegistry.cs @@ -33,8 +33,14 @@ namespace StardewModdingAPI.Framework public void Add(IModMetadata metadata) { this.Mods.Add(metadata); - if (!metadata.IsContentPack) - this.ModNamesByAssembly[metadata.Mod.GetType().Assembly.FullName] = metadata; + } + + /// Track a mod's assembly for use via . + /// The mod metadata. + /// The mod assembly. + public void TrackAssemblies(IModMetadata metadata, Assembly modAssembly) + { + this.ModNamesByAssembly[modAssembly.FullName] = metadata; } /// Get metadata for all loaded mods. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 27c0c40b..46e1de8d 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -977,6 +977,7 @@ namespace StardewModdingAPI.Framework try { modAssembly = assemblyLoader.Load(mod, assemblyPath, assumeCompatible: mod.DataRecord?.Status == ModStatus.AssumeCompatible); + this.ModRegistry.TrackAssemblies(mod, modAssembly); } catch (IncompatibleInstructionException) // details already in trace logs { -- cgit From e627a8a5e5a93df15a4a7c502231254e7c26c976 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 3 Jan 2019 18:41:46 -0500 Subject: avoid period after URLs in log output --- src/SMAPI/Framework/SCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 46e1de8d..ec3e9f72 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -982,7 +982,7 @@ namespace StardewModdingAPI.Framework catch (IncompatibleInstructionException) // details already in trace logs { string[] updateUrls = new[] { modDatabase.GetModPageUrlFor(manifest.UniqueID), "https://mods.smapi.io" }.Where(p => p != null).ToArray(); - errorReasonPhrase = $"it's no longer compatible. Please check for a new version at {string.Join(" or ", updateUrls)}."; + errorReasonPhrase = $"it's no longer compatible. Please check for a new version at {string.Join(" or ", updateUrls)}"; return false; } catch (SAssemblyLoadFailedException ex) -- cgit From 11c080962b3eb927f61d982f910725b255b1ec77 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 3 Jan 2019 18:44:09 -0500 Subject: fix cursor position not updated in edge case --- src/SMAPI/Framework/Input/SInputState.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs index 0228db0d..96a7003a 100644 --- a/src/SMAPI/Framework/Input/SInputState.cs +++ b/src/SMAPI/Framework/Input/SInputState.cs @@ -20,6 +20,9 @@ namespace StardewModdingAPI.Framework.Input /// The cursor position on the screen adjusted for the zoom level. private CursorPosition CursorPositionImpl; + /// The player's last known tile position. + private Vector2? LastPlayerTile; + /********* ** Accessors @@ -83,13 +86,14 @@ namespace StardewModdingAPI.Framework.Input MouseState realMouse = Mouse.GetState(); var activeButtons = this.DeriveStatuses(this.ActiveButtons, realKeyboard, realMouse, realController); Vector2 cursorAbsolutePos = new Vector2(realMouse.X + Game1.viewport.X, realMouse.Y + Game1.viewport.Y); + Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.getTileLocation() : (Vector2?)null; // update real states this.ActiveButtons = activeButtons; this.RealController = realController; this.RealKeyboard = realKeyboard; this.RealMouse = realMouse; - if (this.CursorPositionImpl?.AbsolutePixels != cursorAbsolutePos) + if (cursorAbsolutePos != this.CursorPositionImpl?.AbsolutePixels || playerTilePos != this.LastPlayerTile) this.CursorPositionImpl = this.GetCursorPosition(realMouse, cursorAbsolutePos); // update suppressed states -- cgit From 5d9a618bec8d65d04d3f0b554b281d68289a4499 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 5 Jan 2019 14:47:50 -0500 Subject: fix incorrect 'bypassed safety checks' for mods using LoadStageChanged event --- src/SMAPI/Metadata/InstructionMetadata.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 9ff99440..272ceb09 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -51,7 +51,8 @@ namespace StardewModdingAPI.Metadata yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerialiser); yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.farmerSerializer), InstructionHandleResult.DetectedSaveSerialiser); yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerialiser); - yield return new TypeFinder(typeof(ISpecialisedEvents).FullName, InstructionHandleResult.DetectedUnvalidatedUpdateTick); + yield return new EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicked), InstructionHandleResult.DetectedUnvalidatedUpdateTick); + yield return new EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicking), InstructionHandleResult.DetectedUnvalidatedUpdateTick); #if !SMAPI_3_0_STRICT yield return new EventFinder(typeof(SpecialisedEvents).FullName, nameof(SpecialisedEvents.UnvalidatedUpdateTick), InstructionHandleResult.DetectedUnvalidatedUpdateTick); #endif -- cgit From 90c5858cf8a75a7f236a5fc58d23379e2116c482 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 5 Jan 2019 22:51:38 -0500 Subject: fix typo --- src/SMAPI/Framework/ModHelpers/DataHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ModHelpers/DataHelper.cs b/src/SMAPI/Framework/ModHelpers/DataHelper.cs index 2cb886ba..3b5c1752 100644 --- a/src/SMAPI/Framework/ModHelpers/DataHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/DataHelper.cs @@ -97,7 +97,7 @@ namespace StardewModdingAPI.Framework.ModHelpers if (!Game1.hasLoadedGame) throw new InvalidOperationException($"Can't use {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.WriteSaveData)} when a save file isn't loaded."); if (!Game1.IsMasterGame) - throw new InvalidOperationException($"Can't use {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.ReadSaveData)} because this isn't the main player. (Save files are stored on the main player's computer.)"); + throw new InvalidOperationException($"Can't use {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.WriteSaveData)} because this isn't the main player. (Save files are stored on the main player's computer.)"); string internalKey = this.GetSaveFileKey(key); if (data != null) -- cgit From e3a0bd7e29e0e05bb574786268c30ff82dcc433d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 9 Jan 2019 22:52:40 -0500 Subject: deprecate entry DLL with case-insensitive match --- src/SMAPI/Framework/ModLoading/ModResolver.cs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 835b0a54..a8564524 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -137,12 +137,23 @@ namespace StardewModdingAPI.Framework.ModLoading } // invalid path - string assemblyPath = Path.Combine(mod.DirectoryPath, mod.Manifest.EntryDll); - if (!File.Exists(assemblyPath)) + if (!File.Exists(Path.Combine(mod.DirectoryPath, mod.Manifest.EntryDll))) { mod.SetStatus(ModMetadataStatus.Failed, $"its DLL '{mod.Manifest.EntryDll}' doesn't exist."); continue; } + + // invalid capitalisation + string actualFilename = new DirectoryInfo(mod.DirectoryPath).GetFiles(mod.Manifest.EntryDll).FirstOrDefault()?.Name; + if (actualFilename != mod.Manifest.EntryDll) + { +#if SMAPI_3_0_STRICT + mod.SetStatus(ModMetadataStatus.Failed, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalisation '{actualFilename}'. The capitalisation must match for crossplatform compatibility."); + continue; +#else + SCore.DeprecationManager.Warn(mod.DisplayName, $"{nameof(IManifest.EntryDll)} value with case-insensitive capitalisation", "2.11", DeprecationLevel.Info); +#endif + } } // validate content pack -- cgit From 59bc63cab6cd7fa80a4f46734fdaafde80e5b351 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 20 Jan 2019 01:01:26 -0500 Subject: propagate asset changes into the save file being loaded --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index d83fc748..92968271 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -677,7 +677,13 @@ namespace StardewModdingAPI.Metadata /// Get all locations in the game. private IEnumerable GetLocations() { - foreach (GameLocation location in Game1.locations) + // get available root locations + IEnumerable rootLocations = Game1.locations; + if (SaveGame.loaded?.locations != null) + rootLocations = rootLocations.Concat(SaveGame.loaded.locations); + + // yield root + child locations + foreach (GameLocation location in rootLocations) { yield return location; -- cgit From 7a0ef8086724d31f4145442addb2d40a1b744e6d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 30 Jan 2019 16:33:11 -0500 Subject: fix error propagating NPC sprites if they're not initialised yet --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 92968271..53d930f5 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -529,7 +529,7 @@ namespace StardewModdingAPI.Metadata { // get NPCs NPC[] characters = this.GetCharacters() - .Where(npc => this.GetNormalisedPath(npc.Sprite.textureName.Value) == key) + .Where(npc => npc.Sprite != null && this.GetNormalisedPath(npc.Sprite.textureName.Value) == key) .ToArray(); if (!characters.Any()) return false; -- cgit From 1d25edc2a5a81b52c8de8ce98725de6705e8bbb3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Feb 2019 20:05:46 -0500 Subject: fix assets not disposed correctly in some cases --- src/SMAPI/Framework/ContentCoordinator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index 4dd1b6e1..ee654081 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -228,7 +228,7 @@ namespace StardewModdingAPI.Framework { IAssetInfo info = new AssetInfo(locale, assetName, type, this.MainContentManager.AssertAndNormaliseAssetName); return predicate(info); - }); + }, dispose); } /// Purge matched assets from the cache. -- cgit From 6b6ccb87de4d669f66e0c1a5b9270607db16484c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Feb 2019 20:47:57 -0500 Subject: fix error with custom map tilesheets in some cases Specifically, when a custom map has a seasonal tilesheet which only exists the Content/Maps folder and already matches the current season. --- src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index dac627ba..7c353003 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -319,7 +319,7 @@ namespace StardewModdingAPI.Framework.ModHelpers foreach (string candidateKey in new[] { imageSource, $@"Maps\{imageSource}" }) { string contentKey = candidateKey.EndsWith(".png") - ? candidateKey.Substring(0, imageSource.Length - 4) + ? candidateKey.Substring(0, candidateKey.Length - 4) : candidateKey; try -- cgit From f540d2ab29e06e7f94af927da5f56e03da20f849 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 6 Feb 2019 22:46:18 -0500 Subject: add locale to context trace logs --- src/SMAPI/Framework/SGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index a90e8264..9818314a 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -513,7 +513,7 @@ namespace StardewModdingAPI.Framework 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}."; + string context = $"Context: loaded save '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}, locale set to {this.ContentCore.Language}."; if (Context.IsMultiplayer) { int onlineCount = Game1.getOnlineFarmers().Count(); -- cgit From 215574f2b9bb18f98bd9ce208c58e741384aada6 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 8 Feb 2019 18:19:28 -0500 Subject: fix error when swapping maps mid-session for a location with interior doors --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 53d930f5..a64dc89b 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.Xna.Framework; +using System.Reflection; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Reflection; using StardewValley; @@ -99,8 +99,21 @@ namespace StardewModdingAPI.Metadata { if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalisedPath(location.mapPath.Value) == key) { + // reload map data this.Reflection.GetMethod(location, "reloadMap").Invoke(); this.Reflection.GetMethod(location, "updateWarps").Invoke(); + + // reload doors + { + Type interiorDoorDictType = Type.GetType($"StardewValley.InteriorDoorDictionary, {Constants.GameAssemblyName}", throwOnError: true); + ConstructorInfo constructor = interiorDoorDictType.GetConstructor(new[] { typeof(GameLocation) }); + if (constructor == null) + throw new InvalidOperationException("Can't reset location doors: constructor not found for InteriorDoorDictionary type."); + object instance = constructor.Invoke(new object[] { location }); + + this.Reflection.GetField(location, "interiorDoors").SetValue(instance); + } + anyChanged = true; } } -- cgit From 41f77f51c0203fa36c1e47cf67409244ed3c2ff2 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 8 Feb 2019 18:19:47 -0500 Subject: prepare for 2.10.2 release --- src/SMAPI/Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index f8d1638e..51c15269 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -20,7 +20,7 @@ namespace StardewModdingAPI ** Public ****/ /// SMAPI's current semantic version. - public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.10.1"); + public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.10.2"); /// The minimum supported version of Stardew Valley. public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.32"); -- cgit