From e55295385b592f422d43f0b525cf3bea7be19b52 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 31 Dec 2018 13:54:06 -0500 Subject: add HasFile content pack method --- src/SMAPI/Framework/ContentPack.cs | 27 +++++++++++++++++++++++---- src/SMAPI/IContentPack.cs | 4 ++++ 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs index e39d03a1..5384d98f 100644 --- a/src/SMAPI/Framework/ContentPack.cs +++ b/src/SMAPI/Framework/ContentPack.cs @@ -47,6 +47,15 @@ namespace StardewModdingAPI.Framework this.JsonHelper = jsonHelper; } + /// Get whether a given file exists in the content pack. + /// The file path to check. + public bool HasFile(string path) + { + this.AssertRelativePath(path, nameof(this.HasFile)); + + return File.Exists(Path.Combine(this.DirectoryPath, path)); + } + /// Read a JSON file from the content pack folder. /// The model type. /// The file path relative to the contnet directory. @@ -54,8 +63,7 @@ namespace StardewModdingAPI.Framework /// The is not relative or contains directory climbing (../). public TModel ReadJsonFile(string path) where TModel : class { - if (!PathUtilities.IsSafeRelativePath(path)) - throw new InvalidOperationException($"You must call {nameof(IContentPack)}.{nameof(this.ReadJsonFile)} with a relative path."); + this.AssertRelativePath(path, nameof(this.ReadJsonFile)); path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path)); return this.JsonHelper.ReadJsonFileIfExists(path, out TModel model) @@ -70,8 +78,7 @@ namespace StardewModdingAPI.Framework /// The is not relative or contains directory climbing (../). public void WriteJsonFile(string path, TModel data) where TModel : class { - if (!PathUtilities.IsSafeRelativePath(path)) - throw new InvalidOperationException($"You must call {nameof(IContentPack)}.{nameof(this.WriteJsonFile)} with a relative path."); + this.AssertRelativePath(path, nameof(this.WriteJsonFile)); path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path)); this.JsonHelper.WriteJsonFile(path, data); @@ -95,5 +102,17 @@ namespace StardewModdingAPI.Framework return this.Content.GetActualAssetKey(key, ContentSource.ModFolder); } + + /********* + ** Private methods + *********/ + /// Assert that a relative path was passed it to a content pack method. + /// The path to check. + /// The name of the method which was invoked. + private void AssertRelativePath(string path, string methodName) + { + if (!PathUtilities.IsSafeRelativePath(path)) + throw new InvalidOperationException($"You must call {nameof(IContentPack)}.{methodName} with a relative path."); + } } } diff --git a/src/SMAPI/IContentPack.cs b/src/SMAPI/IContentPack.cs index 9ba32394..32cbc6fc 100644 --- a/src/SMAPI/IContentPack.cs +++ b/src/SMAPI/IContentPack.cs @@ -21,6 +21,10 @@ namespace StardewModdingAPI /********* ** Public methods *********/ + /// Get whether a given file exists in the content pack. + /// The file path to check. + bool HasFile(string path); + /// Read a JSON file from the content pack folder. /// The model type. This should be a plain class that has public properties for the data you want. The properties can be complex types. /// The file path relative to the content pack directory. -- cgit From 31a49b83c2fda9f3990e953aeaefc2b415333f31 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 4 Jan 2019 18:32:12 -0500 Subject: update NuGet packages --- docs/release-notes.md | 1 + .../SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 2 +- src/SMAPI.Tests/StardewModdingAPI.Tests.csproj | 4 ++-- src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj | 4 ++-- src/SMAPI.Web/StardewModdingAPI.Web.csproj | 4 ++-- src/SMAPI/StardewModdingAPI.csproj | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index aae5cf3a..efbd7ddb 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ These changes have not been released yet. * For modders: * Added `IContentPack.HasFile` method. + * Updated to Json.NET 12.0.1. ## 2.11.3 Released 13 September 2019 for Stardew Valley 1.3.36. diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index 45953eec..747a1d69 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/SMAPI.Tests/StardewModdingAPI.Tests.csproj b/src/SMAPI.Tests/StardewModdingAPI.Tests.csproj index 1cb2d1e6..68cf7b34 100644 --- a/src/SMAPI.Tests/StardewModdingAPI.Tests.csproj +++ b/src/SMAPI.Tests/StardewModdingAPI.Tests.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj b/src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj index 46d38f17..a386fc5e 100644 --- a/src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj +++ b/src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/src/SMAPI.Web/StardewModdingAPI.Web.csproj b/src/SMAPI.Web/StardewModdingAPI.Web.csproj index d47361bd..88a13f7b 100644 --- a/src/SMAPI.Web/StardewModdingAPI.Web.csproj +++ b/src/SMAPI.Web/StardewModdingAPI.Web.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index eda53025..718366a7 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -19,7 +19,7 @@ - + -- cgit From 4a297e29eb0c97be799ee3939e9747dc1c631427 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 18 Feb 2019 01:33:10 -0500 Subject: better handle player reconnecting before disconnection is registered --- docs/release-notes.md | 1 + src/SMAPI/Framework/SMultiplayer.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 7724904b..3041dbd3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ These changes have not been released yet. * For players: * Fixed Save Backup not pruning old backups if they're uncompressed. + * Fixed issues when a farmhand reconnects before the game notices they're disconnected. * For modders: * Added `IContentPack.HasFile` method. diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index 0241ef02..dde71092 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -201,7 +201,8 @@ namespace StardewModdingAPI.Framework MultiplayerPeer newPeer = new MultiplayerPeer(message.FarmerID, model, sendMessage, isHost: false); if (this.Peers.ContainsKey(message.FarmerID)) { - this.Monitor.Log($"Rejected mod context from farmhand {message.FarmerID}: already received context for that player.", LogLevel.Error); + this.Monitor.Log($"Received mod context from farmhand {message.FarmerID}, but the game didn't see them disconnect. This may indicate issues with the network connection.", LogLevel.Info); + this.Peers.Remove(message.FarmerID); return; } this.AddPeer(newPeer, canBeHost: false, raiseEvent: false); -- cgit From bad2ac2a29b8775be97133e4c4cfb67a4a7406ee Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 24 Feb 2019 19:56:08 -0500 Subject: remove deprecated APIs (#606) --- docs/release-notes.md | 1 + docs/technical-docs.md | 1 - .../ISemanticVersion.cs | 6 - src/SMAPI.Toolkit/SemanticVersion.cs | 19 +- .../Converters/SemanticVersionConverter.cs | 14 +- src/SMAPI/Constants.cs | 26 +-- src/SMAPI/Events/ContentEvents.cs | 45 ---- src/SMAPI/Events/ControlEvents.cs | 123 ---------- src/SMAPI/Events/EventArgsClickableMenuChanged.cs | 33 --- src/SMAPI/Events/EventArgsClickableMenuClosed.cs | 28 --- .../Events/EventArgsControllerButtonPressed.cs | 34 --- .../Events/EventArgsControllerButtonReleased.cs | 34 --- .../Events/EventArgsControllerTriggerPressed.cs | 39 ---- .../Events/EventArgsControllerTriggerReleased.cs | 39 ---- src/SMAPI/Events/EventArgsInput.cs | 64 ----- src/SMAPI/Events/EventArgsIntChanged.cs | 32 --- src/SMAPI/Events/EventArgsInventoryChanged.cs | 43 ---- src/SMAPI/Events/EventArgsKeyPressed.cs | 28 --- src/SMAPI/Events/EventArgsKeyboardStateChanged.cs | 33 --- src/SMAPI/Events/EventArgsLevelUp.cs | 55 ----- .../Events/EventArgsLocationBuildingsChanged.cs | 41 ---- .../Events/EventArgsLocationObjectsChanged.cs | 42 ---- src/SMAPI/Events/EventArgsLocationsChanged.cs | 35 --- src/SMAPI/Events/EventArgsMineLevelChanged.cs | 32 --- src/SMAPI/Events/EventArgsMouseStateChanged.cs | 44 ---- src/SMAPI/Events/EventArgsPlayerWarped.cs | 34 --- src/SMAPI/Events/EventArgsValueChanged.cs | 33 --- src/SMAPI/Events/GameEvents.cs | 122 ---------- src/SMAPI/Events/GraphicsEvents.cs | 120 ---------- src/SMAPI/Events/InputEvents.cs | 56 ----- src/SMAPI/Events/LocationEvents.cs | 67 ------ src/SMAPI/Events/MenuEvents.cs | 56 ----- src/SMAPI/Events/MineEvents.cs | 45 ---- src/SMAPI/Events/MultiplayerEvents.cs | 78 ------- src/SMAPI/Events/PlayerEvents.cs | 68 ------ src/SMAPI/Events/SaveEvents.cs | 100 -------- src/SMAPI/Events/SpecialisedEvents.cs | 45 ---- src/SMAPI/Events/TimeEvents.cs | 56 ----- .../Framework/Content/AssetDataForDictionary.cs | 33 --- src/SMAPI/Framework/DeprecationManager.cs | 29 --- src/SMAPI/Framework/Events/EventManager.cs | 260 --------------------- src/SMAPI/Framework/Events/ManagedEvent.cs | 105 +++++---- src/SMAPI/Framework/Events/ManagedEventBase.cs | 93 -------- src/SMAPI/Framework/ModHelpers/ModHelper.cs | 71 +----- src/SMAPI/Framework/ModLoading/ModResolver.cs | 4 - src/SMAPI/Framework/SCore.cs | 40 +--- src/SMAPI/Framework/SGame.cs | 207 +--------------- src/SMAPI/Framework/SMultiplayer.cs | 18 -- src/SMAPI/IAssetDataForDictionary.cs | 27 +-- src/SMAPI/IModHelper.cs | 38 --- src/SMAPI/Metadata/InstructionMetadata.cs | 3 - src/SMAPI/SemanticVersion.cs | 14 -- 52 files changed, 65 insertions(+), 2648 deletions(-) delete mode 100644 src/SMAPI/Events/ContentEvents.cs delete mode 100644 src/SMAPI/Events/ControlEvents.cs delete mode 100644 src/SMAPI/Events/EventArgsClickableMenuChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsClickableMenuClosed.cs delete mode 100644 src/SMAPI/Events/EventArgsControllerButtonPressed.cs delete mode 100644 src/SMAPI/Events/EventArgsControllerButtonReleased.cs delete mode 100644 src/SMAPI/Events/EventArgsControllerTriggerPressed.cs delete mode 100644 src/SMAPI/Events/EventArgsControllerTriggerReleased.cs delete mode 100644 src/SMAPI/Events/EventArgsInput.cs delete mode 100644 src/SMAPI/Events/EventArgsIntChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsInventoryChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsKeyPressed.cs delete mode 100644 src/SMAPI/Events/EventArgsKeyboardStateChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsLevelUp.cs delete mode 100644 src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsLocationObjectsChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsLocationsChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsMineLevelChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsMouseStateChanged.cs delete mode 100644 src/SMAPI/Events/EventArgsPlayerWarped.cs delete mode 100644 src/SMAPI/Events/EventArgsValueChanged.cs delete mode 100644 src/SMAPI/Events/GameEvents.cs delete mode 100644 src/SMAPI/Events/GraphicsEvents.cs delete mode 100644 src/SMAPI/Events/InputEvents.cs delete mode 100644 src/SMAPI/Events/LocationEvents.cs delete mode 100644 src/SMAPI/Events/MenuEvents.cs delete mode 100644 src/SMAPI/Events/MineEvents.cs delete mode 100644 src/SMAPI/Events/MultiplayerEvents.cs delete mode 100644 src/SMAPI/Events/PlayerEvents.cs delete mode 100644 src/SMAPI/Events/SaveEvents.cs delete mode 100644 src/SMAPI/Events/SpecialisedEvents.cs delete mode 100644 src/SMAPI/Events/TimeEvents.cs delete mode 100644 src/SMAPI/Framework/Events/ManagedEventBase.cs (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 3041dbd3..2f01ee93 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,6 +8,7 @@ These changes have not been released yet. * For modders: * Added `IContentPack.HasFile` method. + * Dropped support for all deprecated APIs. * Updated to Json.NET 12.0.1. ## 2.11.3 diff --git a/docs/technical-docs.md b/docs/technical-docs.md index 98dd3540..545f4aa3 100644 --- a/docs/technical-docs.md +++ b/docs/technical-docs.md @@ -106,7 +106,6 @@ SMAPI uses a small number of conditional compilation constants, which you can se flag | purpose ---- | ------- `SMAPI_FOR_WINDOWS` | Whether SMAPI is being compiled on Windows for players on Windows. Set automatically in `crossplatform.targets`. -`SMAPI_3_0_STRICT` | Whether to exclude all deprecated APIs from compilation. This is useful for testing mods for SMAPI 3.0 compatibility. # SMAPI web services ## Overview diff --git a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs index 0a6e5758..4a61f9ae 100644 --- a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs +++ b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs @@ -17,12 +17,6 @@ namespace StardewModdingAPI /// The patch version for backwards-compatible bug fixes. int PatchVersion { get; } -#if !SMAPI_3_0_STRICT - /// An optional build tag. - [Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")] - string Build { get; } -#endif - /// An optional prerelease tag. string PrereleaseTag { get; } diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs index ba9ca6c6..78b4c007 100644 --- a/src/SMAPI.Toolkit/SemanticVersion.cs +++ b/src/SMAPI.Toolkit/SemanticVersion.cs @@ -42,15 +42,6 @@ namespace StardewModdingAPI.Toolkit /// An optional prerelease tag. public string PrereleaseTag { get; } -#if !SMAPI_3_0_STRICT - /// An optional prerelease tag. - [Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")] - public string Build => this.PrereleaseTag; - - /// Whether the version was parsed from the legacy object format. - public bool IsLegacyFormat { get; } -#endif - /********* ** Public methods @@ -60,20 +51,12 @@ namespace StardewModdingAPI.Toolkit /// The minor version incremented for backwards-compatible changes. /// The patch version for backwards-compatible fixes. /// An optional prerelease tag. - /// Whether the version was parsed from the legacy object format. - public SemanticVersion(int major, int minor, int patch, string prereleaseTag = null -#if !SMAPI_3_0_STRICT - , bool isLegacyFormat = false -#endif - ) + public SemanticVersion(int major, int minor, int patch, string prereleaseTag = null) { this.MajorVersion = major; this.MinorVersion = minor; this.PatchVersion = patch; this.PrereleaseTag = this.GetNormalisedTag(prereleaseTag); -#if !SMAPI_3_0_STRICT - this.IsLegacyFormat = isLegacyFormat; -#endif this.AssertValid(); } diff --git a/src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs b/src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs index aca06849..c50de4db 100644 --- a/src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs +++ b/src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs @@ -67,20 +67,8 @@ namespace StardewModdingAPI.Toolkit.Serialisation.Converters int minor = obj.ValueIgnoreCase(nameof(ISemanticVersion.MinorVersion)); int patch = obj.ValueIgnoreCase(nameof(ISemanticVersion.PatchVersion)); string prereleaseTag = obj.ValueIgnoreCase(nameof(ISemanticVersion.PrereleaseTag)); -#if !SMAPI_3_0_STRICT - if (string.IsNullOrWhiteSpace(prereleaseTag)) - { - prereleaseTag = obj.ValueIgnoreCase("Build"); - if (prereleaseTag == "0") - prereleaseTag = null; // '0' from incorrect examples in old SMAPI documentation - } -#endif - return new SemanticVersion(major, minor, patch, prereleaseTag -#if !SMAPI_3_0_STRICT - , isLegacyFormat: true -#endif - ); + return new SemanticVersion(major, minor, patch, prereleaseTag); } /// Read a JSON string. diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 9d686e2f..736a10ea 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -44,32 +44,10 @@ namespace StardewModdingAPI public static string SavesPath { get; } = Path.Combine(Constants.DataPath, "Saves"); /// 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 - } - } + public static string SaveFolderName => 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 - } - } + public static string CurrentSavePath => Constants.GetSaveFolderPathIfExists(); /**** ** Internal diff --git a/src/SMAPI/Events/ContentEvents.cs b/src/SMAPI/Events/ContentEvents.cs deleted file mode 100644 index aca76ef7..00000000 --- a/src/SMAPI/Events/ContentEvents.cs +++ /dev/null @@ -1,45 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when the game loads content. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class ContentEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised after the content language changes. - public static event EventHandler> AfterLocaleChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ContentEvents.EventManager.Legacy_LocaleChanged.Add(value); - } - remove => ContentEvents.EventManager.Legacy_LocaleChanged.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - ContentEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/ControlEvents.cs b/src/SMAPI/Events/ControlEvents.cs deleted file mode 100644 index 45aedc9b..00000000 --- a/src/SMAPI/Events/ControlEvents.cs +++ /dev/null @@ -1,123 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework.Input; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when the player uses a controller, keyboard, or mouse. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class ControlEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised when the changes. That happens when the player presses or releases a key. - public static event EventHandler KeyboardChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_KeyboardChanged.Add(value); - } - remove => ControlEvents.EventManager.Legacy_KeyboardChanged.Remove(value); - } - - /// Raised after the player presses a keyboard key. - public static event EventHandler KeyPressed - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_KeyPressed.Add(value); - } - remove => ControlEvents.EventManager.Legacy_KeyPressed.Remove(value); - } - - /// Raised after the player releases a keyboard key. - public static event EventHandler KeyReleased - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_KeyReleased.Add(value); - } - remove => ControlEvents.EventManager.Legacy_KeyReleased.Remove(value); - } - - /// Raised when the changes. That happens when the player moves the mouse, scrolls the mouse wheel, or presses/releases a button. - public static event EventHandler MouseChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_MouseChanged.Add(value); - } - remove => ControlEvents.EventManager.Legacy_MouseChanged.Remove(value); - } - - /// The player pressed a controller button. This event isn't raised for trigger buttons. - public static event EventHandler ControllerButtonPressed - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_ControllerButtonPressed.Add(value); - } - remove => ControlEvents.EventManager.Legacy_ControllerButtonPressed.Remove(value); - } - - /// The player released a controller button. This event isn't raised for trigger buttons. - public static event EventHandler ControllerButtonReleased - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_ControllerButtonReleased.Add(value); - } - remove => ControlEvents.EventManager.Legacy_ControllerButtonReleased.Remove(value); - } - - /// The player pressed a controller trigger button. - public static event EventHandler ControllerTriggerPressed - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_ControllerTriggerPressed.Add(value); - } - remove => ControlEvents.EventManager.Legacy_ControllerTriggerPressed.Remove(value); - } - - /// The player released a controller trigger button. - public static event EventHandler ControllerTriggerReleased - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - ControlEvents.EventManager.Legacy_ControllerTriggerReleased.Add(value); - } - remove => ControlEvents.EventManager.Legacy_ControllerTriggerReleased.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - ControlEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsClickableMenuChanged.cs b/src/SMAPI/Events/EventArgsClickableMenuChanged.cs deleted file mode 100644 index a0b903b7..00000000 --- a/src/SMAPI/Events/EventArgsClickableMenuChanged.cs +++ /dev/null @@ -1,33 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewValley.Menus; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsClickableMenuChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The previous menu. - public IClickableMenu NewMenu { get; } - - /// The current menu. - public IClickableMenu PriorMenu { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The previous menu. - /// The current menu. - public EventArgsClickableMenuChanged(IClickableMenu priorMenu, IClickableMenu newMenu) - { - this.NewMenu = newMenu; - this.PriorMenu = priorMenu; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsClickableMenuClosed.cs b/src/SMAPI/Events/EventArgsClickableMenuClosed.cs deleted file mode 100644 index 77db69ea..00000000 --- a/src/SMAPI/Events/EventArgsClickableMenuClosed.cs +++ /dev/null @@ -1,28 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewValley.Menus; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsClickableMenuClosed : EventArgs - { - /********* - ** Accessors - *********/ - /// The menu that was closed. - public IClickableMenu PriorMenu { get; } - - - /********* - ** Accessors - *********/ - /// Construct an instance. - /// The menu that was closed. - public EventArgsClickableMenuClosed(IClickableMenu priorMenu) - { - this.PriorMenu = priorMenu; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsControllerButtonPressed.cs b/src/SMAPI/Events/EventArgsControllerButtonPressed.cs deleted file mode 100644 index 949446e1..00000000 --- a/src/SMAPI/Events/EventArgsControllerButtonPressed.cs +++ /dev/null @@ -1,34 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsControllerButtonPressed : EventArgs - { - /********* - ** Accessors - *********/ - /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; } - - /// The controller button that was pressed. - public Buttons ButtonPressed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player who pressed the button. - /// The controller button that was pressed. - public EventArgsControllerButtonPressed(PlayerIndex playerIndex, Buttons button) - { - this.PlayerIndex = playerIndex; - this.ButtonPressed = button; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsControllerButtonReleased.cs b/src/SMAPI/Events/EventArgsControllerButtonReleased.cs deleted file mode 100644 index d6d6d840..00000000 --- a/src/SMAPI/Events/EventArgsControllerButtonReleased.cs +++ /dev/null @@ -1,34 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsControllerButtonReleased : EventArgs - { - /********* - ** Accessors - *********/ - /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; } - - /// The controller button that was pressed. - public Buttons ButtonReleased { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player who pressed the button. - /// The controller button that was released. - public EventArgsControllerButtonReleased(PlayerIndex playerIndex, Buttons button) - { - this.PlayerIndex = playerIndex; - this.ButtonReleased = button; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsControllerTriggerPressed.cs b/src/SMAPI/Events/EventArgsControllerTriggerPressed.cs deleted file mode 100644 index 33be2fa3..00000000 --- a/src/SMAPI/Events/EventArgsControllerTriggerPressed.cs +++ /dev/null @@ -1,39 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsControllerTriggerPressed : EventArgs - { - /********* - ** Accessors - *********/ - /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; } - - /// The controller button that was pressed. - public Buttons ButtonPressed { get; } - - /// The current trigger value. - public float Value { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player who pressed the trigger button. - /// The trigger button that was pressed. - /// The current trigger value. - public EventArgsControllerTriggerPressed(PlayerIndex playerIndex, Buttons button, float value) - { - this.PlayerIndex = playerIndex; - this.ButtonPressed = button; - this.Value = value; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsControllerTriggerReleased.cs b/src/SMAPI/Events/EventArgsControllerTriggerReleased.cs deleted file mode 100644 index e90ff712..00000000 --- a/src/SMAPI/Events/EventArgsControllerTriggerReleased.cs +++ /dev/null @@ -1,39 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsControllerTriggerReleased : EventArgs - { - /********* - ** Accessors - *********/ - /// The player who pressed the button. - public PlayerIndex PlayerIndex { get; } - - /// The controller button that was released. - public Buttons ButtonReleased { get; } - - /// The current trigger value. - public float Value { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player who pressed the trigger button. - /// The trigger button that was released. - /// The current trigger value. - public EventArgsControllerTriggerReleased(PlayerIndex playerIndex, Buttons button, float value) - { - this.PlayerIndex = playerIndex; - this.ButtonReleased = button; - this.Value = value; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs deleted file mode 100644 index 5cff3408..00000000 --- a/src/SMAPI/Events/EventArgsInput.cs +++ /dev/null @@ -1,64 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using System.Collections.Generic; - -namespace StardewModdingAPI.Events -{ - /// Event arguments when a button is pressed or released. - public class EventArgsInput : EventArgs - { - /********* - ** Fields - *********/ - /// The buttons to suppress. - private readonly HashSet SuppressButtons; - - - /********* - ** Accessors - *********/ - /// The button on the controller, keyboard, or mouse. - public SButton Button { get; } - - /// The current cursor position. - public ICursorPosition Cursor { get; } - - /// Whether the input should trigger actions on the affected tile. - public bool IsActionButton => this.Button.IsActionButton(); - - /// Whether the input should use tools on the affected tile. - public bool IsUseToolButton => this.Button.IsUseToolButton(); - - /// Whether a mod has indicated the key was already handled. - public bool IsSuppressed => this.SuppressButtons.Contains(this.Button); - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The button on the controller, keyboard, or mouse. - /// The cursor position. - /// The buttons to suppress. - public EventArgsInput(SButton button, ICursorPosition cursor, HashSet suppressButtons) - { - this.Button = button; - this.Cursor = cursor; - this.SuppressButtons = suppressButtons; - } - - /// Prevent the game from handling the current button press. This doesn't prevent other mods from receiving the event. - public void SuppressButton() - { - this.SuppressButton(this.Button); - } - - /// Prevent the game from handling a button press. This doesn't prevent other mods from receiving the event. - /// The button to suppress. - public void SuppressButton(SButton button) - { - this.SuppressButtons.Add(button); - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsIntChanged.cs b/src/SMAPI/Events/EventArgsIntChanged.cs deleted file mode 100644 index 76ec6d08..00000000 --- a/src/SMAPI/Events/EventArgsIntChanged.cs +++ /dev/null @@ -1,32 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for an integer field that changed value. - public class EventArgsIntChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The previous value. - public int PriorInt { get; } - - /// The current value. - public int NewInt { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The previous value. - /// The current value. - public EventArgsIntChanged(int priorInt, int newInt) - { - this.PriorInt = priorInt; - this.NewInt = newInt; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsInventoryChanged.cs b/src/SMAPI/Events/EventArgsInventoryChanged.cs deleted file mode 100644 index 488dd23f..00000000 --- a/src/SMAPI/Events/EventArgsInventoryChanged.cs +++ /dev/null @@ -1,43 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using System.Collections.Generic; -using System.Linq; -using StardewValley; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsInventoryChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The player's inventory. - public IList Inventory { get; } - - /// The added items. - public List Added { get; } - - /// The removed items. - public List Removed { get; } - - /// The items whose stack sizes changed. - public List QuantityChanged { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player's inventory. - /// The inventory changes. - public EventArgsInventoryChanged(IList inventory, ItemStackChange[] changedItems) - { - this.Inventory = inventory; - this.Added = changedItems.Where(n => n.ChangeType == ChangeType.Added).ToList(); - this.Removed = changedItems.Where(n => n.ChangeType == ChangeType.Removed).ToList(); - this.QuantityChanged = changedItems.Where(n => n.ChangeType == ChangeType.StackChange).ToList(); - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsKeyPressed.cs b/src/SMAPI/Events/EventArgsKeyPressed.cs deleted file mode 100644 index 6204d821..00000000 --- a/src/SMAPI/Events/EventArgsKeyPressed.cs +++ /dev/null @@ -1,28 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework.Input; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsKeyPressed : EventArgs - { - /********* - ** Accessors - *********/ - /// The keyboard button that was pressed. - public Keys KeyPressed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The keyboard button that was pressed. - public EventArgsKeyPressed(Keys key) - { - this.KeyPressed = key; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsKeyboardStateChanged.cs b/src/SMAPI/Events/EventArgsKeyboardStateChanged.cs deleted file mode 100644 index 2c3203b1..00000000 --- a/src/SMAPI/Events/EventArgsKeyboardStateChanged.cs +++ /dev/null @@ -1,33 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework.Input; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsKeyboardStateChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The previous keyboard state. - public KeyboardState NewState { get; } - - /// The current keyboard state. - public KeyboardState PriorState { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The previous keyboard state. - /// The current keyboard state. - public EventArgsKeyboardStateChanged(KeyboardState priorState, KeyboardState newState) - { - this.PriorState = priorState; - this.NewState = newState; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsLevelUp.cs b/src/SMAPI/Events/EventArgsLevelUp.cs deleted file mode 100644 index 06c70088..00000000 --- a/src/SMAPI/Events/EventArgsLevelUp.cs +++ /dev/null @@ -1,55 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Enums; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsLevelUp : EventArgs - { - /********* - ** Accessors - *********/ - /// The player skill that leveled up. - public LevelType Type { get; } - - /// The new skill level. - public int NewLevel { get; } - - /// The player skill types. - public enum LevelType - { - /// The combat skill. - Combat = SkillType.Combat, - - /// The farming skill. - Farming = SkillType.Farming, - - /// The fishing skill. - Fishing = SkillType.Fishing, - - /// The foraging skill. - Foraging = SkillType.Foraging, - - /// The mining skill. - Mining = SkillType.Mining, - - /// The luck skill. - Luck = SkillType.Luck - } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player skill that leveled up. - /// The new skill level. - public EventArgsLevelUp(LevelType type, int newLevel) - { - this.Type = type; - this.NewLevel = newLevel; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs b/src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs deleted file mode 100644 index 25e84722..00000000 --- a/src/SMAPI/Events/EventArgsLocationBuildingsChanged.cs +++ /dev/null @@ -1,41 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using System.Collections.Generic; -using System.Linq; -using StardewValley; -using StardewValley.Buildings; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsLocationBuildingsChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The location which changed. - public GameLocation Location { get; } - - /// The buildings added to the location. - public IEnumerable Added { get; } - - /// The buildings removed from the location. - public IEnumerable Removed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The location which changed. - /// The buildings added to the location. - /// The buildings removed from the location. - public EventArgsLocationBuildingsChanged(GameLocation location, IEnumerable added, IEnumerable removed) - { - this.Location = location; - this.Added = added.ToArray(); - this.Removed = removed.ToArray(); - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs b/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs deleted file mode 100644 index 9ca2e3e2..00000000 --- a/src/SMAPI/Events/EventArgsLocationObjectsChanged.cs +++ /dev/null @@ -1,42 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Xna.Framework; -using StardewValley; -using SObject = StardewValley.Object; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsLocationObjectsChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The location which changed. - public GameLocation Location { get; } - - /// The objects added to the location. - public IEnumerable> Added { get; } - - /// The objects removed from the location. - public IEnumerable> Removed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The location which changed. - /// The objects added to the location. - /// The objects removed from the location. - public EventArgsLocationObjectsChanged(GameLocation location, IEnumerable> added, IEnumerable> removed) - { - this.Location = location; - this.Added = added.ToArray(); - this.Removed = removed.ToArray(); - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsLocationsChanged.cs b/src/SMAPI/Events/EventArgsLocationsChanged.cs deleted file mode 100644 index 1a59e612..00000000 --- a/src/SMAPI/Events/EventArgsLocationsChanged.cs +++ /dev/null @@ -1,35 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using System.Collections.Generic; -using System.Linq; -using StardewValley; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsLocationsChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The added locations. - public IEnumerable Added { get; } - - /// The removed locations. - public IEnumerable Removed { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The added locations. - /// The removed locations. - public EventArgsLocationsChanged(IEnumerable added, IEnumerable removed) - { - this.Added = added.ToArray(); - this.Removed = removed.ToArray(); - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsMineLevelChanged.cs b/src/SMAPI/Events/EventArgsMineLevelChanged.cs deleted file mode 100644 index c63b04e9..00000000 --- a/src/SMAPI/Events/EventArgsMineLevelChanged.cs +++ /dev/null @@ -1,32 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsMineLevelChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The previous mine level. - public int PreviousMineLevel { get; } - - /// The current mine level. - public int CurrentMineLevel { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The previous mine level. - /// The current mine level. - public EventArgsMineLevelChanged(int previousMineLevel, int currentMineLevel) - { - this.PreviousMineLevel = previousMineLevel; - this.CurrentMineLevel = currentMineLevel; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsMouseStateChanged.cs b/src/SMAPI/Events/EventArgsMouseStateChanged.cs deleted file mode 100644 index 09f3f759..00000000 --- a/src/SMAPI/Events/EventArgsMouseStateChanged.cs +++ /dev/null @@ -1,44 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsMouseStateChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The previous mouse state. - public MouseState PriorState { get; } - - /// The current mouse state. - public MouseState NewState { get; } - - /// The previous mouse position on the screen adjusted for the zoom level. - public Point PriorPosition { get; } - - /// The current mouse position on the screen adjusted for the zoom level. - public Point NewPosition { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The previous mouse state. - /// The current mouse state. - /// The previous mouse position on the screen adjusted for the zoom level. - /// The current mouse position on the screen adjusted for the zoom level. - public EventArgsMouseStateChanged(MouseState priorState, MouseState newState, Point priorPosition, Point newPosition) - { - this.PriorState = priorState; - this.NewState = newState; - this.PriorPosition = priorPosition; - this.NewPosition = newPosition; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsPlayerWarped.cs b/src/SMAPI/Events/EventArgsPlayerWarped.cs deleted file mode 100644 index d1aa1588..00000000 --- a/src/SMAPI/Events/EventArgsPlayerWarped.cs +++ /dev/null @@ -1,34 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewValley; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a event. - public class EventArgsPlayerWarped : EventArgs - { - /********* - ** Accessors - *********/ - /// The player's previous location. - public GameLocation PriorLocation { get; } - - /// The player's current location. - public GameLocation NewLocation { get; } - - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The player's previous location. - /// The player's current location. - public EventArgsPlayerWarped(GameLocation priorLocation, GameLocation newLocation) - { - this.NewLocation = newLocation; - this.PriorLocation = priorLocation; - } - } -} -#endif diff --git a/src/SMAPI/Events/EventArgsValueChanged.cs b/src/SMAPI/Events/EventArgsValueChanged.cs deleted file mode 100644 index 7bfac7a2..00000000 --- a/src/SMAPI/Events/EventArgsValueChanged.cs +++ /dev/null @@ -1,33 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; - -namespace StardewModdingAPI.Events -{ - /// Event arguments for a field that changed value. - /// The value type. - public class EventArgsValueChanged : EventArgs - { - /********* - ** Accessors - *********/ - /// The previous value. - public T PriorValue { get; } - - /// The current value. - public T NewValue { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The previous value. - /// The current value. - public EventArgsValueChanged(T priorValue, T newValue) - { - this.PriorValue = priorValue; - this.NewValue = newValue; - } - } -} -#endif diff --git a/src/SMAPI/Events/GameEvents.cs b/src/SMAPI/Events/GameEvents.cs deleted file mode 100644 index 9d945277..00000000 --- a/src/SMAPI/Events/GameEvents.cs +++ /dev/null @@ -1,122 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when the game changes state. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class GameEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised when the game updates its state (≈60 times per second). - public static event EventHandler UpdateTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_UpdateTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_UpdateTick.Remove(value); - } - - /// Raised every other tick (≈30 times per second). - public static event EventHandler SecondUpdateTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_SecondUpdateTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_SecondUpdateTick.Remove(value); - } - - /// Raised every fourth tick (≈15 times per second). - public static event EventHandler FourthUpdateTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_FourthUpdateTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_FourthUpdateTick.Remove(value); - } - - /// Raised every eighth tick (≈8 times per second). - public static event EventHandler EighthUpdateTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_EighthUpdateTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_EighthUpdateTick.Remove(value); - } - - /// Raised every 15th tick (≈4 times per second). - public static event EventHandler QuarterSecondTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_QuarterSecondTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_QuarterSecondTick.Remove(value); - } - - /// Raised every 30th tick (≈twice per second). - public static event EventHandler HalfSecondTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_HalfSecondTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_HalfSecondTick.Remove(value); - } - - /// Raised every 60th tick (≈once per second). - public static event EventHandler OneSecondTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_OneSecondTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_OneSecondTick.Remove(value); - } - - /// Raised once after the game initialises and all methods have been called. - public static event EventHandler FirstUpdateTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GameEvents.EventManager.Legacy_FirstUpdateTick.Add(value); - } - remove => GameEvents.EventManager.Legacy_FirstUpdateTick.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - GameEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/GraphicsEvents.cs b/src/SMAPI/Events/GraphicsEvents.cs deleted file mode 100644 index 24a16a29..00000000 --- a/src/SMAPI/Events/GraphicsEvents.cs +++ /dev/null @@ -1,120 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised during the game's draw loop, when the game is rendering content to the window. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class GraphicsEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised after the game window is resized. - public static event EventHandler Resize - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GraphicsEvents.EventManager.Legacy_Resize.Add(value); - } - remove => GraphicsEvents.EventManager.Legacy_Resize.Remove(value); - } - - /**** - ** Main render events - ****/ - /// Raised before drawing the world to the screen. - public static event EventHandler OnPreRenderEvent - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GraphicsEvents.EventManager.Legacy_OnPreRenderEvent.Add(value); - } - remove => GraphicsEvents.EventManager.Legacy_OnPreRenderEvent.Remove(value); - } - - /// Raised after drawing the world to the screen. - public static event EventHandler OnPostRenderEvent - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GraphicsEvents.EventManager.Legacy_OnPostRenderEvent.Add(value); - } - remove => GraphicsEvents.EventManager.Legacy_OnPostRenderEvent.Remove(value); - } - - /**** - ** HUD events - ****/ - /// Raised before drawing the HUD (item toolbar, clock, etc) to the screen. The HUD is available at this point, but not necessarily visible. (For example, the event is raised even if a menu is open.) - public static event EventHandler OnPreRenderHudEvent - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GraphicsEvents.EventManager.Legacy_OnPreRenderHudEvent.Add(value); - } - remove => GraphicsEvents.EventManager.Legacy_OnPreRenderHudEvent.Remove(value); - } - - /// Raised after drawing the HUD (item toolbar, clock, etc) to the screen. The HUD is available at this point, but not necessarily visible. (For example, the event is raised even if a menu is open.) - public static event EventHandler OnPostRenderHudEvent - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GraphicsEvents.EventManager.Legacy_OnPostRenderHudEvent.Add(value); - } - remove => GraphicsEvents.EventManager.Legacy_OnPostRenderHudEvent.Remove(value); - } - - /**** - ** GUI events - ****/ - /// Raised before drawing a menu to the screen during a draw loop. This includes the game's internal menus like the title screen. - public static event EventHandler OnPreRenderGuiEvent - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GraphicsEvents.EventManager.Legacy_OnPreRenderGuiEvent.Add(value); - } - remove => GraphicsEvents.EventManager.Legacy_OnPreRenderGuiEvent.Remove(value); - } - - /// Raised after drawing a menu to the screen during a draw loop. This includes the game's internal menus like the title screen. - public static event EventHandler OnPostRenderGuiEvent - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - GraphicsEvents.EventManager.Legacy_OnPostRenderGuiEvent.Add(value); - } - remove => GraphicsEvents.EventManager.Legacy_OnPostRenderGuiEvent.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - GraphicsEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/InputEvents.cs b/src/SMAPI/Events/InputEvents.cs deleted file mode 100644 index c5ab8c83..00000000 --- a/src/SMAPI/Events/InputEvents.cs +++ /dev/null @@ -1,56 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when the player uses a controller, keyboard, or mouse button. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class InputEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised when the player presses a button on the keyboard, controller, or mouse. - public static event EventHandler ButtonPressed - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - InputEvents.EventManager.Legacy_ButtonPressed.Add(value); - } - remove => InputEvents.EventManager.Legacy_ButtonPressed.Remove(value); - } - - /// Raised when the player releases a keyboard key on the keyboard, controller, or mouse. - public static event EventHandler ButtonReleased - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - InputEvents.EventManager.Legacy_ButtonReleased.Add(value); - } - remove => InputEvents.EventManager.Legacy_ButtonReleased.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - InputEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/LocationEvents.cs b/src/SMAPI/Events/LocationEvents.cs deleted file mode 100644 index 0761bdd8..00000000 --- a/src/SMAPI/Events/LocationEvents.cs +++ /dev/null @@ -1,67 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when the player transitions between game locations, a location is added or removed, or the objects in the current location change. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class LocationEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised after a game location is added or removed. - public static event EventHandler LocationsChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - LocationEvents.EventManager.Legacy_LocationsChanged.Add(value); - } - remove => LocationEvents.EventManager.Legacy_LocationsChanged.Remove(value); - } - - /// Raised after buildings are added or removed in a location. - public static event EventHandler BuildingsChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - LocationEvents.EventManager.Legacy_BuildingsChanged.Add(value); - } - remove => LocationEvents.EventManager.Legacy_BuildingsChanged.Remove(value); - } - - /// Raised after objects are added or removed in a location. - public static event EventHandler ObjectsChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - LocationEvents.EventManager.Legacy_ObjectsChanged.Add(value); - } - remove => LocationEvents.EventManager.Legacy_ObjectsChanged.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - LocationEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/MenuEvents.cs b/src/SMAPI/Events/MenuEvents.cs deleted file mode 100644 index 8647c268..00000000 --- a/src/SMAPI/Events/MenuEvents.cs +++ /dev/null @@ -1,56 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when a game menu is opened or closed (including internal menus like the title screen). - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class MenuEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised after a game menu is opened or replaced with another menu. This event is not invoked when a menu is closed. - public static event EventHandler MenuChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - MenuEvents.EventManager.Legacy_MenuChanged.Add(value); - } - remove => MenuEvents.EventManager.Legacy_MenuChanged.Remove(value); - } - - /// Raised after a game menu is closed. - public static event EventHandler MenuClosed - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - MenuEvents.EventManager.Legacy_MenuClosed.Add(value); - } - remove => MenuEvents.EventManager.Legacy_MenuClosed.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - MenuEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/MineEvents.cs b/src/SMAPI/Events/MineEvents.cs deleted file mode 100644 index 929da35b..00000000 --- a/src/SMAPI/Events/MineEvents.cs +++ /dev/null @@ -1,45 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when something happens in the mines. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class MineEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised after the player warps to a new level of the mine. - public static event EventHandler MineLevelChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - MineEvents.EventManager.Legacy_MineLevelChanged.Add(value); - } - remove => MineEvents.EventManager.Legacy_MineLevelChanged.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - MineEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/MultiplayerEvents.cs b/src/SMAPI/Events/MultiplayerEvents.cs deleted file mode 100644 index 0650a8e2..00000000 --- a/src/SMAPI/Events/MultiplayerEvents.cs +++ /dev/null @@ -1,78 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised during the multiplayer sync process. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class MultiplayerEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised before the game syncs changes from other players. - public static event EventHandler BeforeMainSync - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - MultiplayerEvents.EventManager.Legacy_BeforeMainSync.Add(value); - } - remove => MultiplayerEvents.EventManager.Legacy_BeforeMainSync.Remove(value); - } - - /// Raised after the game syncs changes from other players. - public static event EventHandler AfterMainSync - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - MultiplayerEvents.EventManager.Legacy_AfterMainSync.Add(value); - } - remove => MultiplayerEvents.EventManager.Legacy_AfterMainSync.Remove(value); - } - - /// Raised before the game broadcasts changes to other players. - public static event EventHandler BeforeMainBroadcast - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - MultiplayerEvents.EventManager.Legacy_BeforeMainBroadcast.Add(value); - } - remove => MultiplayerEvents.EventManager.Legacy_BeforeMainBroadcast.Remove(value); - } - - /// Raised after the game broadcasts changes to other players. - public static event EventHandler AfterMainBroadcast - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - MultiplayerEvents.EventManager.Legacy_AfterMainBroadcast.Add(value); - } - remove => MultiplayerEvents.EventManager.Legacy_AfterMainBroadcast.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - MultiplayerEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/PlayerEvents.cs b/src/SMAPI/Events/PlayerEvents.cs deleted file mode 100644 index 11ba1e54..00000000 --- a/src/SMAPI/Events/PlayerEvents.cs +++ /dev/null @@ -1,68 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when the player data changes. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class PlayerEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised after the player's inventory changes in any way (added or removed item, sorted, etc). - public static event EventHandler InventoryChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - PlayerEvents.EventManager.Legacy_InventoryChanged.Add(value); - } - remove => PlayerEvents.EventManager.Legacy_InventoryChanged.Remove(value); - } - - /// Raised after the player levels up a skill. This happens as soon as they level up, not when the game notifies the player after their character goes to bed. - public static event EventHandler LeveledUp - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - PlayerEvents.EventManager.Legacy_LeveledUp.Add(value); - } - remove => PlayerEvents.EventManager.Legacy_LeveledUp.Remove(value); - } - - /// Raised after the player warps to a new location. - public static event EventHandler Warped - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - PlayerEvents.EventManager.Legacy_PlayerWarped.Add(value); - } - remove => PlayerEvents.EventManager.Legacy_PlayerWarped.Remove(value); - } - - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - PlayerEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/SaveEvents.cs b/src/SMAPI/Events/SaveEvents.cs deleted file mode 100644 index da276d22..00000000 --- a/src/SMAPI/Events/SaveEvents.cs +++ /dev/null @@ -1,100 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised before and after the player saves/loads the game. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class SaveEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised before the game creates the save file. - public static event EventHandler BeforeCreate - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - SaveEvents.EventManager.Legacy_BeforeCreateSave.Add(value); - } - remove => SaveEvents.EventManager.Legacy_BeforeCreateSave.Remove(value); - } - - /// Raised after the game finishes creating the save file. - public static event EventHandler AfterCreate - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - SaveEvents.EventManager.Legacy_AfterCreateSave.Add(value); - } - remove => SaveEvents.EventManager.Legacy_AfterCreateSave.Remove(value); - } - - /// Raised before the game begins writes data to the save file. - public static event EventHandler BeforeSave - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - SaveEvents.EventManager.Legacy_BeforeSave.Add(value); - } - remove => SaveEvents.EventManager.Legacy_BeforeSave.Remove(value); - } - - /// Raised after the game finishes writing data to the save file. - public static event EventHandler AfterSave - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - SaveEvents.EventManager.Legacy_AfterSave.Add(value); - } - remove => SaveEvents.EventManager.Legacy_AfterSave.Remove(value); - } - - /// Raised after the player loads a save slot. - public static event EventHandler AfterLoad - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - SaveEvents.EventManager.Legacy_AfterLoad.Add(value); - } - remove => SaveEvents.EventManager.Legacy_AfterLoad.Remove(value); - } - - /// Raised after the game returns to the title screen. - public static event EventHandler AfterReturnToTitle - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - SaveEvents.EventManager.Legacy_AfterReturnToTitle.Add(value); - } - remove => SaveEvents.EventManager.Legacy_AfterReturnToTitle.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - SaveEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/SpecialisedEvents.cs b/src/SMAPI/Events/SpecialisedEvents.cs deleted file mode 100644 index 4f16e4da..00000000 --- a/src/SMAPI/Events/SpecialisedEvents.cs +++ /dev/null @@ -1,45 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events serving specialised edge cases that shouldn't be used by most mods. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class SpecialisedEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised when the game updates its state (≈60 times per second), regardless of normal SMAPI validation. This event is not thread-safe and may be invoked while game logic is running asynchronously. Changes to game state in this method may crash the game or corrupt an in-progress save. Do not use this event unless you're fully aware of the context in which your code will be run. Mods using this method will trigger a stability warning in the SMAPI console. - public static event EventHandler UnvalidatedUpdateTick - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - SpecialisedEvents.EventManager.Legacy_UnvalidatedUpdateTick.Add(value); - } - remove => SpecialisedEvents.EventManager.Legacy_UnvalidatedUpdateTick.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - SpecialisedEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Events/TimeEvents.cs b/src/SMAPI/Events/TimeEvents.cs deleted file mode 100644 index 389532d9..00000000 --- a/src/SMAPI/Events/TimeEvents.cs +++ /dev/null @@ -1,56 +0,0 @@ -#if !SMAPI_3_0_STRICT -using System; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Events; - -namespace StardewModdingAPI.Events -{ - /// Events raised when the in-game date or time changes. - [Obsolete("Use " + nameof(Mod.Helper) + "." + nameof(IModHelper.Events) + " instead. See https://smapi.io/3.0 for more info.")] - public static class TimeEvents - { - /********* - ** Fields - *********/ - /// The core event manager. - private static EventManager EventManager; - - - /********* - ** Events - *********/ - /// Raised after the game begins a new day, including when loading a save. - public static event EventHandler AfterDayStarted - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - TimeEvents.EventManager.Legacy_AfterDayStarted.Add(value); - } - remove => TimeEvents.EventManager.Legacy_AfterDayStarted.Remove(value); - } - - /// Raised after the in-game clock changes. - public static event EventHandler TimeOfDayChanged - { - add - { - SCore.DeprecationManager.WarnForOldEvents(); - TimeEvents.EventManager.Legacy_TimeOfDayChanged.Add(value); - } - remove => TimeEvents.EventManager.Legacy_TimeOfDayChanged.Remove(value); - } - - - /********* - ** Public methods - *********/ - /// Initialise the events. - /// The core event manager. - internal static void Init(EventManager eventManager) - { - TimeEvents.EventManager = eventManager; - } - } -} -#endif diff --git a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs index 11a2564c..a331f38a 100644 --- a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs +++ b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace StardewModdingAPI.Framework.Content { @@ -18,37 +17,5 @@ namespace StardewModdingAPI.Framework.Content /// A callback to invoke when the data is replaced (if any). public AssetDataForDictionary(string locale, string assetName, IDictionary data, Func getNormalisedPath, Action> onDataReplaced) : base(locale, assetName, data, getNormalisedPath, onDataReplaced) { } - -#if !SMAPI_3_0_STRICT - /// Add or replace an entry in the dictionary. - /// The entry key. - /// The entry value. - [Obsolete("Access " + nameof(AssetData>.Data) + "field directly.")] - public void Set(TKey key, TValue value) - { - SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.PendingRemoval); - this.Data[key] = value; - } - - /// Add or replace an entry in the dictionary. - /// The entry key. - /// A callback which accepts the current value and returns the new value. - [Obsolete("Access " + nameof(AssetData>.Data) + "field directly.")] - public void Set(TKey key, Func value) - { - SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.PendingRemoval); - this.Data[key] = value(this.Data[key]); - } - - /// Dynamically replace values in the dictionary. - /// A lambda which takes the current key and value for an entry, and returns the new value. - [Obsolete("Access " + nameof(AssetData>.Data) + "field directly.")] - public void Set(Func replacer) - { - SCore.DeprecationManager.Warn($"AssetDataForDictionary.{nameof(Set)}", "2.10", DeprecationLevel.PendingRemoval); - foreach (var pair in this.Data.ToArray()) - this.Data[pair.Key] = replacer(pair.Key, pair.Value); - } -#endif } } diff --git a/src/SMAPI/Framework/DeprecationManager.cs b/src/SMAPI/Framework/DeprecationManager.cs index 984bb487..636b1979 100644 --- a/src/SMAPI/Framework/DeprecationManager.cs +++ b/src/SMAPI/Framework/DeprecationManager.cs @@ -14,11 +14,7 @@ namespace StardewModdingAPI.Framework private readonly HashSet LoggedDeprecations = new HashSet(StringComparer.InvariantCultureIgnoreCase); /// Encapsulates monitoring and logging for a given module. -#if !SMAPI_3_0_STRICT - private readonly Monitor Monitor; -#else private readonly IMonitor Monitor; -#endif /// Tracks the installed mods. private readonly ModRegistry ModRegistry; @@ -26,11 +22,6 @@ namespace StardewModdingAPI.Framework /// The queued deprecation warnings to display. private readonly IList QueuedWarnings = new List(); -#if !SMAPI_3_0_STRICT - /// Whether the one-time deprecation message has been shown. - private bool DeprecationHeaderShown = false; -#endif - /********* ** Public methods @@ -38,11 +29,7 @@ namespace StardewModdingAPI.Framework /// Construct an instance. /// Encapsulates monitoring and logging for a given module. /// Tracks the installed mods. -#if !SMAPI_3_0_STRICT - public DeprecationManager(Monitor monitor, ModRegistry modRegistry) -#else public DeprecationManager(IMonitor monitor, ModRegistry modRegistry) -#endif { this.Monitor = monitor; this.ModRegistry = modRegistry; @@ -81,26 +68,10 @@ namespace StardewModdingAPI.Framework /// Print any queued messages. public void PrintQueued() { -#if !SMAPI_3_0_STRICT - if (!this.DeprecationHeaderShown && this.QueuedWarnings.Any()) - { - this.Monitor.Newline(); - this.Monitor.Log("Some of your mods will break in the upcoming SMAPI 3.0. Please update your mods now, or notify the author if no update is available. See https://mods.smapi.io for links to the latest versions.", LogLevel.Warn); - this.Monitor.Newline(); - this.DeprecationHeaderShown = true; - } -#endif - foreach (DeprecationWarning warning in this.QueuedWarnings.OrderBy(p => p.ModName).ThenBy(p => p.NounPhrase)) { // build message -#if SMAPI_3_0_STRICT string message = $"{warning.ModName} uses deprecated code ({warning.NounPhrase} is deprecated since SMAPI {warning.Version})."; -#else - string message = warning.NounPhrase == "legacy events" - ? $"{warning.ModName ?? "An unknown mod"} will break in the upcoming SMAPI 3.0 (legacy events are deprecated since SMAPI {warning.Version})." - : $"{warning.ModName ?? "An unknown mod"} will break in the upcoming SMAPI 3.0 ({warning.NounPhrase} is deprecated since SMAPI {warning.Version})."; -#endif // get log level LogLevel level; diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 13244601..23879f1d 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -1,7 +1,4 @@ using System.Diagnostics.CodeAnalysis; -#if !SMAPI_3_0_STRICT -using Microsoft.Xna.Framework.Input; -#endif using StardewModdingAPI.Events; namespace StardewModdingAPI.Framework.Events @@ -167,196 +164,6 @@ namespace StardewModdingAPI.Framework.Events public readonly ManagedEvent UnvalidatedUpdateTicked; -#if !SMAPI_3_0_STRICT - /********* - ** Events (old) - *********/ - /**** - ** ContentEvents - ****/ - /// Raised after the content language changes. - public readonly ManagedEvent> Legacy_LocaleChanged; - - /**** - ** ControlEvents - ****/ - /// Raised when the changes. That happens when the player presses or releases a key. - public readonly ManagedEvent Legacy_KeyboardChanged; - - /// Raised after the player presses a keyboard key. - public readonly ManagedEvent Legacy_KeyPressed; - - /// Raised after the player releases a keyboard key. - public readonly ManagedEvent Legacy_KeyReleased; - - /// Raised when the changes. That happens when the player moves the mouse, scrolls the mouse wheel, or presses/releases a button. - public readonly ManagedEvent Legacy_MouseChanged; - - /// The player pressed a controller button. This event isn't raised for trigger buttons. - public readonly ManagedEvent Legacy_ControllerButtonPressed; - - /// The player released a controller button. This event isn't raised for trigger buttons. - public readonly ManagedEvent Legacy_ControllerButtonReleased; - - /// The player pressed a controller trigger button. - public readonly ManagedEvent Legacy_ControllerTriggerPressed; - - /// The player released a controller trigger button. - public readonly ManagedEvent Legacy_ControllerTriggerReleased; - - /**** - ** GameEvents - ****/ - /// Raised once after the game initialises and all methods have been called. - public readonly ManagedEvent Legacy_FirstUpdateTick; - - /// Raised when the game updates its state (≈60 times per second). - public readonly ManagedEvent Legacy_UpdateTick; - - /// Raised every other tick (≈30 times per second). - public readonly ManagedEvent Legacy_SecondUpdateTick; - - /// Raised every fourth tick (≈15 times per second). - public readonly ManagedEvent Legacy_FourthUpdateTick; - - /// Raised every eighth tick (≈8 times per second). - public readonly ManagedEvent Legacy_EighthUpdateTick; - - /// Raised every 15th tick (≈4 times per second). - public readonly ManagedEvent Legacy_QuarterSecondTick; - - /// Raised every 30th tick (≈twice per second). - public readonly ManagedEvent Legacy_HalfSecondTick; - - /// Raised every 60th tick (≈once per second). - public readonly ManagedEvent Legacy_OneSecondTick; - - /**** - ** GraphicsEvents - ****/ - /// Raised after the game window is resized. - public readonly ManagedEvent Legacy_Resize; - - /// Raised before drawing the world to the screen. - public readonly ManagedEvent Legacy_OnPreRenderEvent; - - /// Raised after drawing the world to the screen. - public readonly ManagedEvent Legacy_OnPostRenderEvent; - - /// Raised before drawing the HUD (item toolbar, clock, etc) to the screen. The HUD is available at this point, but not necessarily visible. (For example, the event is raised even if a menu is open.) - public readonly ManagedEvent Legacy_OnPreRenderHudEvent; - - /// Raised after drawing the HUD (item toolbar, clock, etc) to the screen. The HUD is available at this point, but not necessarily visible. (For example, the event is raised even if a menu is open.) - public readonly ManagedEvent Legacy_OnPostRenderHudEvent; - - /// Raised before drawing a menu to the screen during a draw loop. This includes the game's internal menus like the title screen. - public readonly ManagedEvent Legacy_OnPreRenderGuiEvent; - - /// Raised after drawing a menu to the screen during a draw loop. This includes the game's internal menus like the title screen. - public readonly ManagedEvent Legacy_OnPostRenderGuiEvent; - - /**** - ** InputEvents - ****/ - /// Raised after the player presses a button on the keyboard, controller, or mouse. - public readonly ManagedEvent Legacy_ButtonPressed; - - /// Raised after the player releases a keyboard key on the keyboard, controller, or mouse. - public readonly ManagedEvent Legacy_ButtonReleased; - - /**** - ** LocationEvents - ****/ - /// Raised after a game location is added or removed. - public readonly ManagedEvent Legacy_LocationsChanged; - - /// Raised after buildings are added or removed in a location. - public readonly ManagedEvent Legacy_BuildingsChanged; - - /// Raised after objects are added or removed in a location. - public readonly ManagedEvent Legacy_ObjectsChanged; - - /**** - ** MenuEvents - ****/ - /// Raised after a game menu is opened or replaced with another menu. This event is not invoked when a menu is closed. - public readonly ManagedEvent Legacy_MenuChanged; - - /// Raised after a game menu is closed. - public readonly ManagedEvent Legacy_MenuClosed; - - /**** - ** MultiplayerEvents - ****/ - /// Raised before the game syncs changes from other players. - public readonly ManagedEvent Legacy_BeforeMainSync; - - /// Raised after the game syncs changes from other players. - public readonly ManagedEvent Legacy_AfterMainSync; - - /// Raised before the game broadcasts changes to other players. - public readonly ManagedEvent Legacy_BeforeMainBroadcast; - - /// Raised after the game broadcasts changes to other players. - public readonly ManagedEvent Legacy_AfterMainBroadcast; - - /**** - ** MineEvents - ****/ - /// Raised after the player warps to a new level of the mine. - public readonly ManagedEvent Legacy_MineLevelChanged; - - /**** - ** PlayerEvents - ****/ - /// Raised after the player's inventory changes in any way (added or removed item, sorted, etc). - public readonly ManagedEvent Legacy_InventoryChanged; - - /// Raised after the player levels up a skill. This happens as soon as they level up, not when the game notifies the player after their character goes to bed. - public readonly ManagedEvent Legacy_LeveledUp; - - /// Raised after the player warps to a new location. - public readonly ManagedEvent Legacy_PlayerWarped; - - - /**** - ** SaveEvents - ****/ - /// Raised before the game creates the save file. - public readonly ManagedEvent Legacy_BeforeCreateSave; - - /// Raised after the game finishes creating the save file. - public readonly ManagedEvent Legacy_AfterCreateSave; - - /// Raised before the game begins writes data to the save file. - public readonly ManagedEvent Legacy_BeforeSave; - - /// Raised after the game finishes writing data to the save file. - public readonly ManagedEvent Legacy_AfterSave; - - /// Raised after the player loads a save slot. - public readonly ManagedEvent Legacy_AfterLoad; - - /// Raised after the game returns to the title screen. - public readonly ManagedEvent Legacy_AfterReturnToTitle; - - /**** - ** SpecialisedEvents - ****/ - /// Raised when the game updates its state (≈60 times per second), regardless of normal SMAPI validation. This event is not thread-safe and may be invoked while game logic is running asynchronously. Changes to game state in this method may crash the game or corrupt an in-progress save. Do not use this event unless you're fully aware of the context in which your code will be run. Mods using this method will trigger a stability warning in the SMAPI console. - public readonly ManagedEvent Legacy_UnvalidatedUpdateTick; - - /**** - ** TimeEvents - ****/ - /// Raised after the game begins a new day, including when loading a save. - public readonly ManagedEvent Legacy_AfterDayStarted; - - /// Raised after the in-game clock changes. - public readonly ManagedEvent Legacy_TimeOfDayChanged; -#endif - - /********* ** Public methods *********/ @@ -367,9 +174,6 @@ namespace StardewModdingAPI.Framework.Events { // create shortcut initialisers ManagedEvent ManageEventOf(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); -#if !SMAPI_3_0_STRICT - ManagedEvent ManageEvent(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); -#endif // init events (new) this.MenuChanged = ManageEventOf(nameof(IModEvents.Display), nameof(IDisplayEvents.MenuChanged)); @@ -422,70 +226,6 @@ namespace StardewModdingAPI.Framework.Events this.LoadStageChanged = ManageEventOf(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.LoadStageChanged)); this.UnvalidatedUpdateTicking = ManageEventOf(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicking)); this.UnvalidatedUpdateTicked = ManageEventOf(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicked)); - -#if !SMAPI_3_0_STRICT - // init events (old) - this.Legacy_LocaleChanged = ManageEventOf>(nameof(ContentEvents), nameof(ContentEvents.AfterLocaleChanged)); - - this.Legacy_ControllerButtonPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerButtonPressed)); - this.Legacy_ControllerButtonReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerButtonReleased)); - this.Legacy_ControllerTriggerPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerTriggerPressed)); - this.Legacy_ControllerTriggerReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.ControllerTriggerReleased)); - this.Legacy_KeyboardChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyboardChanged)); - this.Legacy_KeyPressed = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyPressed)); - this.Legacy_KeyReleased = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.KeyReleased)); - this.Legacy_MouseChanged = ManageEventOf(nameof(ControlEvents), nameof(ControlEvents.MouseChanged)); - - this.Legacy_FirstUpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.FirstUpdateTick)); - this.Legacy_UpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.UpdateTick)); - this.Legacy_SecondUpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.SecondUpdateTick)); - this.Legacy_FourthUpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.FourthUpdateTick)); - this.Legacy_EighthUpdateTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.EighthUpdateTick)); - this.Legacy_QuarterSecondTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.QuarterSecondTick)); - this.Legacy_HalfSecondTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.HalfSecondTick)); - this.Legacy_OneSecondTick = ManageEvent(nameof(GameEvents), nameof(GameEvents.OneSecondTick)); - - this.Legacy_Resize = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.Resize)); - this.Legacy_OnPreRenderEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPreRenderEvent)); - this.Legacy_OnPostRenderEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPostRenderEvent)); - this.Legacy_OnPreRenderHudEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPreRenderHudEvent)); - this.Legacy_OnPostRenderHudEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPostRenderHudEvent)); - this.Legacy_OnPreRenderGuiEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPreRenderGuiEvent)); - this.Legacy_OnPostRenderGuiEvent = ManageEvent(nameof(GraphicsEvents), nameof(GraphicsEvents.OnPostRenderGuiEvent)); - - this.Legacy_ButtonPressed = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonPressed)); - this.Legacy_ButtonReleased = ManageEventOf(nameof(InputEvents), nameof(InputEvents.ButtonReleased)); - - this.Legacy_LocationsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.LocationsChanged)); - this.Legacy_BuildingsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.BuildingsChanged)); - this.Legacy_ObjectsChanged = ManageEventOf(nameof(LocationEvents), nameof(LocationEvents.ObjectsChanged)); - - this.Legacy_MenuChanged = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuChanged)); - this.Legacy_MenuClosed = ManageEventOf(nameof(MenuEvents), nameof(MenuEvents.MenuClosed)); - - this.Legacy_BeforeMainBroadcast = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.BeforeMainBroadcast)); - this.Legacy_AfterMainBroadcast = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.AfterMainBroadcast)); - this.Legacy_BeforeMainSync = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.BeforeMainSync)); - this.Legacy_AfterMainSync = ManageEvent(nameof(MultiplayerEvents), nameof(MultiplayerEvents.AfterMainSync)); - - this.Legacy_MineLevelChanged = ManageEventOf(nameof(MineEvents), nameof(MineEvents.MineLevelChanged)); - - this.Legacy_InventoryChanged = ManageEventOf(nameof(PlayerEvents), nameof(PlayerEvents.InventoryChanged)); - this.Legacy_LeveledUp = ManageEventOf(nameof(PlayerEvents), nameof(PlayerEvents.LeveledUp)); - this.Legacy_PlayerWarped = ManageEventOf(nameof(PlayerEvents), nameof(PlayerEvents.Warped)); - - this.Legacy_BeforeCreateSave = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.BeforeCreate)); - this.Legacy_AfterCreateSave = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.AfterCreate)); - this.Legacy_BeforeSave = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.BeforeSave)); - this.Legacy_AfterSave = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.AfterSave)); - this.Legacy_AfterLoad = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.AfterLoad)); - this.Legacy_AfterReturnToTitle = ManageEvent(nameof(SaveEvents), nameof(SaveEvents.AfterReturnToTitle)); - - this.Legacy_UnvalidatedUpdateTick = ManageEvent(nameof(SpecialisedEvents), nameof(SpecialisedEvents.UnvalidatedUpdateTick)); - - this.Legacy_AfterDayStarted = ManageEvent(nameof(TimeEvents), nameof(TimeEvents.AfterDayStarted)); - this.Legacy_TimeOfDayChanged = ManageEventOf(nameof(TimeEvents), nameof(TimeEvents.TimeOfDayChanged)); -#endif } } } diff --git a/src/SMAPI/Framework/Events/ManagedEvent.cs b/src/SMAPI/Framework/Events/ManagedEvent.cs index f9e7f6ec..2afe7a03 100644 --- a/src/SMAPI/Framework/Events/ManagedEvent.cs +++ b/src/SMAPI/Framework/Events/ManagedEvent.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; using System.Linq; namespace StardewModdingAPI.Framework.Events { /// An event wrapper which intercepts and logs errors in handler code. /// The event arguments type. - internal class ManagedEvent : ManagedEventBase> + internal class ManagedEvent { /********* ** Fields @@ -13,6 +14,21 @@ namespace StardewModdingAPI.Framework.Events /// The underlying event. private event EventHandler Event; + /// A human-readable name for the event. + private readonly string EventName; + + /// Writes messages to the log. + private readonly IMonitor Monitor; + + /// The mod registry with which to identify mods. + protected readonly ModRegistry ModRegistry; + + /// The display names for the mods which added each delegate. + private readonly IDictionary, IModMetadata> SourceMods = new Dictionary, IModMetadata>(); + + /// The cached invocation list. + private EventHandler[] CachedInvocationList; + /********* ** Public methods @@ -22,7 +38,17 @@ namespace StardewModdingAPI.Framework.Events /// Writes messages to the log. /// The mod registry with which to identify mods. public ManagedEvent(string eventName, IMonitor monitor, ModRegistry modRegistry) - : base(eventName, monitor, modRegistry) { } + { + this.EventName = eventName; + this.Monitor = monitor; + this.ModRegistry = modRegistry; + } + + /// Get whether anything is listening to the event. + public bool HasListeners() + { + return this.CachedInvocationList?.Length > 0; + } /// Add an event handler. /// The event handler. @@ -91,71 +117,50 @@ namespace StardewModdingAPI.Framework.Events } } } - } - -#if !SMAPI_3_0_STRICT - /// An event wrapper which intercepts and logs errors in handler code. - internal class ManagedEvent : ManagedEventBase - { - /********* - ** Fields - *********/ - /// The underlying event. - private event EventHandler Event; /********* - ** Public methods + ** Private methods *********/ - /// Construct an instance. - /// A human-readable name for the event. - /// Writes messages to the log. - /// The mod registry with which to identify mods. - public ManagedEvent(string eventName, IMonitor monitor, ModRegistry modRegistry) - : base(eventName, monitor, modRegistry) { } - - /// Add an event handler. + /// Track an event handler. + /// The mod which added the handler. /// The event handler. - public void Add(EventHandler handler) + /// The updated event invocation list. + protected void AddTracking(IModMetadata mod, EventHandler handler, IEnumerable> invocationList) { - this.Add(handler, this.ModRegistry.GetFromStack()); + this.SourceMods[handler] = mod; + this.CachedInvocationList = invocationList?.ToArray() ?? new EventHandler[0]; } - /// Add an event handler. + /// Remove tracking for an event handler. /// The event handler. - /// The mod which added the event handler. - public void Add(EventHandler handler, IModMetadata mod) + /// The updated event invocation list. + protected void RemoveTracking(EventHandler handler, IEnumerable> invocationList) { - this.Event += handler; - this.AddTracking(mod, handler, this.Event?.GetInvocationList().Cast()); + this.CachedInvocationList = invocationList?.ToArray() ?? new EventHandler[0]; + if (!this.CachedInvocationList.Contains(handler)) // don't remove if there's still a reference to the removed handler (e.g. it was added twice and removed once) + this.SourceMods.Remove(handler); } - /// Remove an event handler. + /// Get the mod which registered the given event handler, if available. /// The event handler. - public void Remove(EventHandler handler) + protected IModMetadata GetSourceMod(EventHandler handler) { - this.Event -= handler; - this.RemoveTracking(handler, this.Event?.GetInvocationList().Cast()); + return this.SourceMods.TryGetValue(handler, out IModMetadata mod) + ? mod + : null; } - /// Raise the event and notify all handlers. - public void Raise() + /// Log an exception from an event handler. + /// The event handler instance. + /// The exception that was raised. + protected void LogError(EventHandler handler, Exception ex) { - if (this.Event == null) - return; - - foreach (EventHandler handler in this.CachedInvocationList) - { - try - { - handler.Invoke(null, EventArgs.Empty); - } - catch (Exception ex) - { - this.LogError(handler, ex); - } - } + IModMetadata mod = this.GetSourceMod(handler); + if (mod != null) + mod.LogAsMod($"This mod failed in the {this.EventName} event. Technical details: \n{ex.GetLogSummary()}", LogLevel.Error); + else + this.Monitor.Log($"A mod failed in the {this.EventName} event. Technical details: \n{ex.GetLogSummary()}", LogLevel.Error); } } -#endif } diff --git a/src/SMAPI/Framework/Events/ManagedEventBase.cs b/src/SMAPI/Framework/Events/ManagedEventBase.cs deleted file mode 100644 index c8c3516b..00000000 --- a/src/SMAPI/Framework/Events/ManagedEventBase.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StardewModdingAPI.Framework.Events -{ - /// The base implementation for an event wrapper which intercepts and logs errors in handler code. - internal abstract class ManagedEventBase - { - /********* - ** Fields - *********/ - /// A human-readable name for the event. - private readonly string EventName; - - /// Writes messages to the log. - private readonly IMonitor Monitor; - - /// The mod registry with which to identify mods. - protected readonly ModRegistry ModRegistry; - - /// The display names for the mods which added each delegate. - private readonly IDictionary SourceMods = new Dictionary(); - - /// The cached invocation list. - protected TEventHandler[] CachedInvocationList { get; private set; } - - - /********* - ** Public methods - *********/ - /// Get whether anything is listening to the event. - public bool HasListeners() - { - return this.CachedInvocationList?.Length > 0; - } - - /********* - ** Protected methods - *********/ - /// Construct an instance. - /// A human-readable name for the event. - /// Writes messages to the log. - /// The mod registry with which to identify mods. - protected ManagedEventBase(string eventName, IMonitor monitor, ModRegistry modRegistry) - { - this.EventName = eventName; - this.Monitor = monitor; - this.ModRegistry = modRegistry; - } - - /// Track an event handler. - /// The mod which added the handler. - /// The event handler. - /// The updated event invocation list. - protected void AddTracking(IModMetadata mod, TEventHandler handler, IEnumerable invocationList) - { - this.SourceMods[handler] = mod; - this.CachedInvocationList = invocationList?.ToArray() ?? new TEventHandler[0]; - } - - /// Remove tracking for an event handler. - /// The event handler. - /// The updated event invocation list. - protected void RemoveTracking(TEventHandler handler, IEnumerable invocationList) - { - this.CachedInvocationList = invocationList?.ToArray() ?? new TEventHandler[0]; - if (!this.CachedInvocationList.Contains(handler)) // don't remove if there's still a reference to the removed handler (e.g. it was added twice and removed once) - this.SourceMods.Remove(handler); - } - - /// Get the mod which registered the given event handler, if available. - /// The event handler. - protected IModMetadata GetSourceMod(TEventHandler handler) - { - return this.SourceMods.TryGetValue(handler, out IModMetadata mod) - ? mod - : null; - } - - /// Log an exception from an event handler. - /// The event handler instance. - /// The exception that was raised. - protected void LogError(TEventHandler handler, Exception ex) - { - IModMetadata mod = this.GetSourceMod(handler); - if (mod != null) - mod.LogAsMod($"This mod failed in the {this.EventName} event. Technical details: \n{ex.GetLogSummary()}", LogLevel.Error); - else - this.Monitor.Log($"A mod failed in the {this.EventName} event. Technical details: \n{ex.GetLogSummary()}", LogLevel.Error); - } - } -} diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index 6c9838c9..86e8eb28 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; using System.IO; using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Input; using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Models; -using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Framework.ModHelpers { @@ -18,11 +15,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The full path to the mod's folder. public string DirectoryPath { get; } -#if !SMAPI_3_0_STRICT - /// Encapsulates SMAPI's JSON file parsing. - private readonly JsonHelper JsonHelper; -#endif - /// Manages access to events raised by SMAPI, which let your mod react when something happens in the game. public IModEvents Events { get; } @@ -60,7 +52,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Construct an instance. /// The mod's unique ID. /// The full path to the mod's folder. - /// Encapsulate SMAPI's JSON parsing. /// Manages the game's input state. /// Manages access to events raised by SMAPI. /// An API for loading content assets. @@ -73,7 +64,7 @@ namespace StardewModdingAPI.Framework.ModHelpers /// An API for reading translations stored in the mod's i18n folder. /// An argument is null or empty. /// The path does not exist on disk. - public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, SInputState inputState, IModEvents events, IContentHelper contentHelper, IContentPackHelper contentPackHelper, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper) + public ModHelper(string modID, string modDirectory, SInputState inputState, IModEvents events, IContentHelper contentHelper, IContentPackHelper contentPackHelper, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper) : base(modID) { // validate directory @@ -94,9 +85,6 @@ namespace StardewModdingAPI.Framework.ModHelpers this.Multiplayer = multiplayer ?? throw new ArgumentNullException(nameof(multiplayer)); this.Translation = translationHelper ?? throw new ArgumentNullException(nameof(translationHelper)); this.Events = events; -#if !SMAPI_3_0_STRICT - this.JsonHelper = jsonHelper ?? throw new ArgumentNullException(nameof(jsonHelper)); -#endif } /**** @@ -121,63 +109,6 @@ namespace StardewModdingAPI.Framework.ModHelpers this.Data.WriteJsonFile("config.json", config); } -#if !SMAPI_3_0_STRICT - /**** - ** Generic JSON files - ****/ - /// Read a JSON file. - /// The model type. - /// The file path relative to the mod directory. - /// Returns the deserialised model, or null if the file doesn't exist or is empty. - [Obsolete("Use " + nameof(ModHelper.Data) + "." + nameof(IDataHelper.ReadJsonFile) + " instead")] - public TModel ReadJsonFile(string path) - where TModel : class - { - path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path)); - return this.JsonHelper.ReadJsonFileIfExists(path, out TModel data) - ? data - : null; - } - - /// Save to a JSON file. - /// The model type. - /// The file path relative to the mod directory. - /// The model to save. - [Obsolete("Use " + nameof(ModHelper.Data) + "." + nameof(IDataHelper.WriteJsonFile) + " instead")] - public void WriteJsonFile(string path, TModel model) - where TModel : class - { - path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path)); - this.JsonHelper.WriteJsonFile(path, model); - } -#endif - - /**** - ** Content packs - ****/ -#if !SMAPI_3_0_STRICT - /// Manually create a transitional content pack to support pre-SMAPI content packs. This provides a way to access legacy content packs using the SMAPI content pack APIs, but the content pack will not be visible in the log or validated by SMAPI. - /// The absolute directory path containing the content pack files. - /// The content pack's unique ID. - /// The content pack name. - /// The content pack description. - /// The content pack author's name. - /// The content pack version. - [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ContentPacks) + "." + nameof(IContentPackHelper.CreateTemporary) + " instead")] - public IContentPack CreateTransitionalContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version) - { - SCore.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.PendingRemoval); - return this.ContentPacks.CreateTemporary(directoryPath, id, name, description, author, version); - } - - /// Get all content packs loaded for this mod. - [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ContentPacks) + "." + nameof(IContentPackHelper.GetOwned) + " instead")] - public IEnumerable GetContentPacks() - { - return this.ContentPacks.GetOwned(); - } -#endif - /**** ** Disposal ****/ diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 75d3849d..f2002530 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -147,12 +147,8 @@ namespace StardewModdingAPI.Framework.ModLoading 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.PendingRemoval); -#endif } } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 5dd52992..06a2e0af 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -190,24 +190,6 @@ namespace StardewModdingAPI.Framework // initialise SMAPI try { -#if !SMAPI_3_0_STRICT - // hook up events - ContentEvents.Init(this.EventManager); - ControlEvents.Init(this.EventManager); - GameEvents.Init(this.EventManager); - GraphicsEvents.Init(this.EventManager); - InputEvents.Init(this.EventManager); - LocationEvents.Init(this.EventManager); - MenuEvents.Init(this.EventManager); - MineEvents.Init(this.EventManager); - MultiplayerEvents.Init(this.EventManager); - PlayerEvents.Init(this.EventManager); - SaveEvents.Init(this.EventManager); - SpecialisedEvents.Init(this.EventManager); - TimeEvents.Init(this.EventManager); -#endif - - // init JSON parser JsonConverter[] converters = { new ColorConverter(), new PointConverter(), @@ -262,10 +244,6 @@ namespace StardewModdingAPI.Framework // set window titles this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion}"; Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion}"; -#if SMAPI_3_0_STRICT - this.GameInstance.Window.Title += " [SMAPI 3.0 strict mode]"; - Console.Title += " [SMAPI 3.0 strict mode]"; -#endif } catch (Exception ex) { @@ -375,9 +353,6 @@ namespace StardewModdingAPI.Framework private void InitialiseAfterGameStart() { // add headers -#if SMAPI_3_0_STRICT - this.Monitor.Log($"You're running SMAPI 3.0 strict mode, so most mods won't work correctly. If that wasn't intended, install the normal version of SMAPI from https://smapi.io instead.", LogLevel.Warn); -#endif if (this.Settings.DeveloperMode) this.Monitor.Log($"You have SMAPI for developers, so the console will be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info); if (!this.Settings.CheckForUpdates) @@ -439,11 +414,6 @@ namespace StardewModdingAPI.Framework int modsLoaded = this.ModRegistry.GetAll().Count(); this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods"; Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion} with {modsLoaded} mods"; -#if SMAPI_3_0_STRICT - this.GameInstance.Window.Title += " [SMAPI 3.0 strict mode]"; - Console.Title += " [SMAPI 3.0 strict mode]"; -#endif - // start SMAPI console new Thread(this.RunConsoleLoop).Start(); @@ -926,14 +896,6 @@ namespace StardewModdingAPI.Framework return false; } -#if !SMAPI_3_0_STRICT - // add deprecation warning for old version format - { - if (mod.Manifest?.Version is Toolkit.SemanticVersion version && version.IsLegacyFormat) - SCore.DeprecationManager.Warn(mod.DisplayName, "non-string manifest version", "2.8", DeprecationLevel.PendingRemoval); - } -#endif - // validate dependencies // Although dependences are validated before mods are loaded, a dependency may have failed to load. if (mod.Manifest.Dependencies?.Any() == true) @@ -1039,7 +1001,7 @@ namespace StardewModdingAPI.Framework return new ContentPack(packDirPath, packManifest, packContentHelper, this.Toolkit.JsonHelper); } - modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.Toolkit.JsonHelper, this.GameInstance.Input, events, contentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper); + modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.GameInstance.Input, events, contentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper); } // init mod diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 704eb6bc..b35e1d71 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -9,9 +9,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -#if !SMAPI_3_0_STRICT -using Microsoft.Xna.Framework.Input; -#endif using Netcode; using StardewModdingAPI.Enums; using StardewModdingAPI.Events; @@ -228,12 +225,7 @@ namespace StardewModdingAPI.Framework // raise events this.Events.LoadStageChanged.Raise(new LoadStageChangedEventArgs(oldStage, newStage)); if (newStage == LoadStage.None) - { this.Events.ReturnedToTitle.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - this.Events.Legacy_AfterReturnToTitle.Raise(); -#endif - } } /// Constructor a content manager to read XNB files. @@ -344,9 +336,6 @@ namespace StardewModdingAPI.Framework SGame.TicksElapsed++; base.Update(gameTime); events.UnvalidatedUpdateTicked.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_UnvalidatedUpdateTick.Raise(); -#endif return; } @@ -393,9 +382,6 @@ namespace StardewModdingAPI.Framework // This should *always* run, even when suppressing mod events, since the game uses // this too. For example, doing this after mod event suppression would prevent the // user from doing anything on the overnight shipping screen. -#if !SMAPI_3_0_STRICT - SInputState previousInputState = this.Input.Clone(); -#endif SInputState inputState = this.Input; if (this.IsActive) inputState.TrueUpdate(); @@ -416,9 +402,6 @@ namespace StardewModdingAPI.Framework this.IsBetweenCreateEvents = true; this.Monitor.Log("Context: before save creation.", LogLevel.Trace); events.SaveCreating.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_BeforeCreateSave.Raise(); -#endif } // raise before-save @@ -427,9 +410,6 @@ namespace StardewModdingAPI.Framework this.IsBetweenSaveEvents = true; this.Monitor.Log("Context: before save.", LogLevel.Trace); events.Saving.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_BeforeSave.Raise(); -#endif } // suppress non-save events @@ -437,9 +417,6 @@ namespace StardewModdingAPI.Framework SGame.TicksElapsed++; base.Update(gameTime); events.UnvalidatedUpdateTicked.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_UnvalidatedUpdateTick.Raise(); -#endif return; } if (this.IsBetweenCreateEvents) @@ -449,9 +426,6 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Context: after save creation, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace); this.OnLoadStageChanged(LoadStage.CreatedSaveFile); events.SaveCreated.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_AfterCreateSave.Raise(); -#endif } if (this.IsBetweenSaveEvents) { @@ -460,10 +434,6 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Context: after save, starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace); events.Saved.RaiseEmpty(); events.DayStarted.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_AfterSave.Raise(); - events.Legacy_AfterDayStarted.Raise(); -#endif } /********* @@ -492,15 +462,8 @@ namespace StardewModdingAPI.Framework *********/ if (this.Watchers.LocaleWatcher.IsChanged) { - var was = this.Watchers.LocaleWatcher.PreviousValue; - var now = this.Watchers.LocaleWatcher.CurrentValue; - - this.Monitor.Log($"Context: locale set to {now}.", LogLevel.Trace); - + this.Monitor.Log($"Context: locale set to {this.Watchers.LocaleWatcher.CurrentValue}.", LogLevel.Trace); this.OnLocaleChanged(); -#if !SMAPI_3_0_STRICT - events.Legacy_LocaleChanged.Raise(new EventArgsValueChanged(was.ToString(), now.ToString())); -#endif this.Watchers.LocaleWatcher.Reset(); } @@ -527,10 +490,6 @@ namespace StardewModdingAPI.Framework this.OnLoadStageChanged(LoadStage.Ready); events.SaveLoaded.RaiseEmpty(); events.DayStarted.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_AfterLoad.Raise(); - events.Legacy_AfterDayStarted.Raise(); -#endif } /********* @@ -549,9 +508,6 @@ namespace StardewModdingAPI.Framework Point newSize = this.Watchers.WindowSizeWatcher.CurrentValue; events.WindowResized.Raise(new WindowResizedEventArgs(oldSize, newSize)); -#if !SMAPI_3_0_STRICT - events.Legacy_Resize.Raise(); -#endif this.Watchers.WindowSizeWatcher.Reset(); } @@ -610,23 +566,6 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Events: button {button} pressed.", LogLevel.Trace); events.ButtonPressed.Raise(new ButtonPressedEventArgs(button, cursor, inputState)); - -#if !SMAPI_3_0_STRICT - // legacy events - events.Legacy_ButtonPressed.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons)); - if (button.TryGetKeyboard(out Keys key)) - { - if (key != Keys.None) - events.Legacy_KeyPressed.Raise(new EventArgsKeyPressed(key)); - } - else if (button.TryGetController(out Buttons controllerButton)) - { - if (controllerButton == Buttons.LeftTrigger || controllerButton == Buttons.RightTrigger) - events.Legacy_ControllerTriggerPressed.Raise(new EventArgsControllerTriggerPressed(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right)); - else - events.Legacy_ControllerButtonPressed.Raise(new EventArgsControllerButtonPressed(PlayerIndex.One, controllerButton)); - } -#endif } else if (status == InputStatus.Released) { @@ -634,33 +573,8 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Events: button {button} released.", LogLevel.Trace); events.ButtonReleased.Raise(new ButtonReleasedEventArgs(button, cursor, inputState)); - -#if !SMAPI_3_0_STRICT - // legacy events - events.Legacy_ButtonReleased.Raise(new EventArgsInput(button, cursor, inputState.SuppressButtons)); - if (button.TryGetKeyboard(out Keys key)) - { - if (key != Keys.None) - events.Legacy_KeyReleased.Raise(new EventArgsKeyPressed(key)); - } - else if (button.TryGetController(out Buttons controllerButton)) - { - if (controllerButton == Buttons.LeftTrigger || controllerButton == Buttons.RightTrigger) - events.Legacy_ControllerTriggerReleased.Raise(new EventArgsControllerTriggerReleased(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right)); - else - events.Legacy_ControllerButtonReleased.Raise(new EventArgsControllerButtonReleased(PlayerIndex.One, controllerButton)); - } -#endif } } - -#if !SMAPI_3_0_STRICT - // raise legacy state-changed events - if (inputState.RealKeyboard != previousInputState.RealKeyboard) - events.Legacy_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard)); - if (inputState.RealMouse != previousInputState.RealMouse) - events.Legacy_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, new Point((int)previousInputState.CursorPosition.ScreenPixels.X, (int)previousInputState.CursorPosition.ScreenPixels.Y), new Point((int)inputState.CursorPosition.ScreenPixels.X, (int)inputState.CursorPosition.ScreenPixels.Y))); -#endif } } @@ -678,12 +592,6 @@ namespace StardewModdingAPI.Framework // raise menu events events.MenuChanged.Raise(new MenuChangedEventArgs(was, now)); -#if !SMAPI_3_0_STRICT - if (now != null) - events.Legacy_MenuChanged.Raise(new EventArgsClickableMenuChanged(was, now)); - else - events.Legacy_MenuClosed.Raise(new EventArgsClickableMenuClosed(was)); -#endif } /********* @@ -711,9 +619,6 @@ namespace StardewModdingAPI.Framework } events.LocationListChanged.Raise(new LocationListChangedEventArgs(added, removed)); -#if !SMAPI_3_0_STRICT - events.Legacy_LocationsChanged.Raise(new EventArgsLocationsChanged(added, removed)); -#endif } // raise location contents changed @@ -730,9 +635,6 @@ namespace StardewModdingAPI.Framework watcher.BuildingsWatcher.Reset(); events.BuildingListChanged.Raise(new BuildingListChangedEventArgs(location, added, removed)); -#if !SMAPI_3_0_STRICT - events.Legacy_BuildingsChanged.Raise(new EventArgsLocationBuildingsChanged(location, added, removed)); -#endif } // debris changed @@ -777,9 +679,6 @@ namespace StardewModdingAPI.Framework watcher.ObjectsWatcher.Reset(); events.ObjectListChanged.Raise(new ObjectListChangedEventArgs(location, added, removed)); -#if !SMAPI_3_0_STRICT - events.Legacy_ObjectsChanged.Raise(new EventArgsLocationObjectsChanged(location, added, removed)); -#endif } // terrain features changed @@ -809,9 +708,6 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Events: time changed from {was} to {now}.", LogLevel.Trace); events.TimeChanged.Raise(new TimeChangedEventArgs(was, now)); -#if !SMAPI_3_0_STRICT - events.Legacy_TimeOfDayChanged.Raise(new EventArgsIntChanged(was, now)); -#endif } else this.Watchers.TimeWatcher.Reset(); @@ -829,9 +725,6 @@ namespace StardewModdingAPI.Framework GameLocation oldLocation = playerTracker.LocationWatcher.PreviousValue; events.Warped.Raise(new WarpedEventArgs(playerTracker.Player, oldLocation, newLocation)); -#if !SMAPI_3_0_STRICT - events.Legacy_PlayerWarped.Raise(new EventArgsPlayerWarped(oldLocation, newLocation)); -#endif } // raise player leveled up a skill @@ -841,9 +734,6 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Events: player skill '{pair.Key}' changed from {pair.Value.PreviousValue} to {pair.Value.CurrentValue}.", LogLevel.Trace); events.LevelChanged.Raise(new LevelChangedEventArgs(playerTracker.Player, pair.Key, pair.Value.PreviousValue, pair.Value.CurrentValue)); -#if !SMAPI_3_0_STRICT - events.Legacy_LeveledUp.Raise(new EventArgsLevelUp((EventArgsLevelUp.LevelType)pair.Key, pair.Value.CurrentValue)); -#endif } // raise player inventory changed @@ -853,9 +743,6 @@ namespace StardewModdingAPI.Framework if (this.Monitor.IsVerbose) this.Monitor.Log("Events: player inventory changed.", LogLevel.Trace); events.InventoryChanged.Raise(new InventoryChangedEventArgs(playerTracker.Player, changedItems)); -#if !SMAPI_3_0_STRICT - events.Legacy_InventoryChanged.Raise(new EventArgsInventoryChanged(Game1.player.Items, changedItems)); -#endif } // raise mine level changed @@ -863,9 +750,6 @@ namespace StardewModdingAPI.Framework { if (this.Monitor.IsVerbose) this.Monitor.Log($"Context: mine level changed to {mineLevel}.", LogLevel.Trace); -#if !SMAPI_3_0_STRICT - events.Legacy_MineLevelChanged.Raise(new EventArgsMineLevelChanged(playerTracker.MineLevelWatcher.PreviousValue, mineLevel)); -#endif } } this.Watchers.CurrentPlayerTracker?.Reset(); @@ -910,25 +794,6 @@ namespace StardewModdingAPI.Framework /********* ** Update events *********/ -#if !SMAPI_3_0_STRICT - events.Legacy_UnvalidatedUpdateTick.Raise(); - if (isFirstTick) - events.Legacy_FirstUpdateTick.Raise(); - events.Legacy_UpdateTick.Raise(); - if (SGame.TicksElapsed % 2 == 0) - events.Legacy_SecondUpdateTick.Raise(); - if (SGame.TicksElapsed % 4 == 0) - events.Legacy_FourthUpdateTick.Raise(); - if (SGame.TicksElapsed % 8 == 0) - events.Legacy_EighthUpdateTick.Raise(); - if (SGame.TicksElapsed % 15 == 0) - events.Legacy_QuarterSecondTick.Raise(); - if (SGame.TicksElapsed % 30 == 0) - events.Legacy_HalfSecondTick.Raise(); - if (SGame.TicksElapsed % 60 == 0) - events.Legacy_OneSecondTick.Raise(); -#endif - this.UpdateCrashTimer.Reset(); } catch (Exception ex) @@ -1014,14 +879,8 @@ namespace StardewModdingAPI.Framework try { events.RenderingActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPreRenderGuiEvent.Raise(); -#endif activeClickableMenu.draw(Game1.spriteBatch); events.RenderedActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderGuiEvent.Raise(); -#endif } catch (Exception ex) { @@ -1029,10 +888,6 @@ namespace StardewModdingAPI.Framework activeClickableMenu.exitThisMenu(); } events.Rendered.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderEvent.Raise(); -#endif - Game1.spriteBatch.End(); } if (Game1.overlayMenu != null) @@ -1055,14 +910,8 @@ namespace StardewModdingAPI.Framework { Game1.activeClickableMenu.drawBackground(Game1.spriteBatch); events.RenderingActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPreRenderGuiEvent.Raise(); -#endif Game1.activeClickableMenu.draw(Game1.spriteBatch); events.RenderedActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderGuiEvent.Raise(); -#endif } catch (Exception ex) { @@ -1070,9 +919,6 @@ namespace StardewModdingAPI.Framework Game1.activeClickableMenu.exitThisMenu(); } events.Rendered.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderEvent.Raise(); -#endif Game1.spriteBatch.End(); this.drawOverlays(Game1.spriteBatch); if ((double)Game1.options.zoomLevel != 1.0) @@ -1097,9 +943,6 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Color(0, (int)byte.MaxValue, 0)); Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); events.Rendered.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderEvent.Raise(); -#endif Game1.spriteBatch.End(); } else if (Game1.currentMinigame != null) @@ -1112,9 +955,6 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.End(); } this.drawOverlays(Game1.spriteBatch); -#if !SMAPI_3_0_STRICT - this.RaisePostRender(needsNewBatch: true); -#endif if ((double)Game1.options.zoomLevel == 1.0) return; this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); @@ -1132,14 +972,8 @@ namespace StardewModdingAPI.Framework try { events.RenderingActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPreRenderGuiEvent.Raise(); -#endif Game1.activeClickableMenu.draw(Game1.spriteBatch); events.RenderedActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderGuiEvent.Raise(); -#endif } catch (Exception ex) { @@ -1229,9 +1063,6 @@ namespace StardewModdingAPI.Framework if (++batchOpens == 1) events.Rendering.RaiseEmpty(); events.RenderingWorld.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPreRenderEvent.Raise(); -#endif if (Game1.background != null) Game1.background.draw(Game1.spriteBatch); Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); @@ -1389,7 +1220,7 @@ namespace StardewModdingAPI.Framework } Game1.drawPlayerHeldObject(Game1.player); } - label_129: + label_129: if ((Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && ((!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool) && (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), (int)Game1.player.Position.Y - 38), Game1.viewport.Size) != null && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null))) Game1.drawTool(Game1.player); if (Game1.currentLocation.Map.GetLayer("AlwaysFront") != null) @@ -1544,14 +1375,8 @@ namespace StardewModdingAPI.Framework if ((Game1.displayHUD || Game1.eventUp) && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && (!Game1.freezeControls && !Game1.panMode && !Game1.HostPaused)) { events.RenderingHud.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPreRenderHudEvent.Raise(); -#endif this.drawHUD(); events.RenderedHud.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderHudEvent.Raise(); -#endif } else if (Game1.activeClickableMenu == null && Game1.farmEvent == null) Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2((float)Game1.getOldMouseX(), (float)Game1.getOldMouseY()), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)(4.0 + (double)Game1.dialogueButtonScale / 150.0), SpriteEffects.None, 1f); @@ -1660,14 +1485,8 @@ namespace StardewModdingAPI.Framework try { events.RenderingActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPreRenderGuiEvent.Raise(); -#endif Game1.activeClickableMenu.draw(Game1.spriteBatch); events.RenderedActiveMenu.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderGuiEvent.Raise(); -#endif } catch (Exception ex) { @@ -1684,9 +1503,6 @@ namespace StardewModdingAPI.Framework } events.Rendered.RaiseEmpty(); -#if !SMAPI_3_0_STRICT - events.Legacy_OnPostRenderEvent.Raise(); -#endif Game1.spriteBatch.End(); this.drawOverlays(Game1.spriteBatch); this.renderScreenBuffer(); @@ -1694,24 +1510,5 @@ namespace StardewModdingAPI.Framework } } } - - /**** - ** Methods - ****/ -#if !SMAPI_3_0_STRICT - /// Raise the if there are any listeners. - /// Whether to create a new sprite batch. - private void RaisePostRender(bool needsNewBatch = false) - { - if (this.Events.Legacy_OnPostRenderEvent.HasListeners()) - { - if (needsNewBatch) - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - this.Events.Legacy_OnPostRenderEvent.Raise(); - if (needsNewBatch) - Game1.spriteBatch.End(); - } - } -#endif } } diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index dde71092..ffe2320b 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -89,24 +89,6 @@ namespace StardewModdingAPI.Framework this.HostPeer = null; } -#if !SMAPI_3_0_STRICT - /// Handle sync messages from other players and perform other initial sync logic. - public override void UpdateEarly() - { - this.EventManager.Legacy_BeforeMainSync.Raise(); - base.UpdateEarly(); - this.EventManager.Legacy_AfterMainSync.Raise(); - } - - /// Broadcast sync messages to other players and perform other final sync logic. - public override void UpdateLate(bool forceSync = false) - { - this.EventManager.Legacy_BeforeMainBroadcast.Raise(); - base.UpdateLate(forceSync); - this.EventManager.Legacy_AfterMainBroadcast.Raise(); - } -#endif - /// Initialise a client before the game connects to a remote server. /// The client to initialise. public override Client InitClient(Client client) diff --git a/src/SMAPI/IAssetDataForDictionary.cs b/src/SMAPI/IAssetDataForDictionary.cs index 911599d9..1136316f 100644 --- a/src/SMAPI/IAssetDataForDictionary.cs +++ b/src/SMAPI/IAssetDataForDictionary.cs @@ -1,32 +1,7 @@ -using System; using System.Collections.Generic; -using StardewModdingAPI.Framework.Content; namespace StardewModdingAPI { /// Encapsulates access and changes to dictionary content being read from a data file. - public interface IAssetDataForDictionary : IAssetData> - { -#if !SMAPI_3_0_STRICT - /********* - ** Public methods - *********/ - /// Add or replace an entry in the dictionary. - /// The entry key. - /// The entry value. - [Obsolete("Access " + nameof(AssetData>.Data) + "field directly.")] - void Set(TKey key, TValue value); - - /// Add or replace an entry in the dictionary. - /// The entry key. - /// A callback which accepts the current value and returns the new value. - [Obsolete("Access " + nameof(AssetData>.Data) + "field directly.")] - void Set(TKey key, Func value); - - /// Dynamically replace values in the dictionary. - /// A lambda which takes the current key and value for an entry, and returns the new value. - [Obsolete("Access " + nameof(AssetData>.Data) + "field directly.")] - void Set(Func replacer); -#endif - } + public interface IAssetDataForDictionary : IAssetData> { } } diff --git a/src/SMAPI/IModHelper.cs b/src/SMAPI/IModHelper.cs index 0220b4f7..cd746e06 100644 --- a/src/SMAPI/IModHelper.cs +++ b/src/SMAPI/IModHelper.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections.Generic; using StardewModdingAPI.Events; namespace StardewModdingAPI @@ -58,41 +56,5 @@ namespace StardewModdingAPI /// The config class type. /// The config settings to save. void WriteConfig(TConfig config) where TConfig : class, new(); - -#if !SMAPI_3_0_STRICT - /**** - ** Generic JSON files - ****/ - /// Read a JSON file. - /// The model type. - /// The file path relative to the mod directory. - /// Returns the deserialised model, or null if the file doesn't exist or is empty. - [Obsolete("Use " + nameof(IModHelper.Data) + "." + nameof(IDataHelper.ReadJsonFile) + " instead")] - TModel ReadJsonFile(string path) where TModel : class; - - /// Save to a JSON file. - /// The model type. - /// The file path relative to the mod directory. - /// The model to save. - [Obsolete("Use " + nameof(IModHelper.Data) + "." + nameof(IDataHelper.WriteJsonFile) + " instead")] - void WriteJsonFile(string path, TModel model) where TModel : class; - - /**** - ** Content packs - ****/ - /// Manually create a transitional content pack to support pre-SMAPI content packs. This provides a way to access legacy content packs using the SMAPI content pack APIs, but the content pack will not be visible in the log or validated by SMAPI. - /// The absolute directory path containing the content pack files. - /// The content pack's unique ID. - /// The content pack name. - /// The content pack description. - /// The content pack author's name. - /// The content pack version. - [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ContentPacks) + "." + nameof(IContentPackHelper.CreateTemporary) + " instead")] - IContentPack CreateTransitionalContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version); - - /// Get all content packs loaded for this mod. - [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ContentPacks) + "." + nameof(IContentPackHelper.GetOwned) + " instead")] - IEnumerable GetContentPacks(); -#endif } } diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 272ceb09..72410d41 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -53,9 +53,6 @@ namespace StardewModdingAPI.Metadata yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerialiser); 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 /**** ** detect paranoid issues diff --git a/src/SMAPI/SemanticVersion.cs b/src/SMAPI/SemanticVersion.cs index ec2d9e40..acdc92f8 100644 --- a/src/SMAPI/SemanticVersion.cs +++ b/src/SMAPI/SemanticVersion.cs @@ -1,6 +1,5 @@ using System; using Newtonsoft.Json; -using StardewModdingAPI.Framework; namespace StardewModdingAPI { @@ -26,19 +25,6 @@ namespace StardewModdingAPI /// The patch version for backwards-compatible bug fixes. public int PatchVersion => this.Version.PatchVersion; -#if !SMAPI_3_0_STRICT - /// An optional build tag. - [Obsolete("Use " + nameof(ISemanticVersion.PrereleaseTag) + " instead")] - public string Build - { - get - { - SCore.DeprecationManager?.Warn($"{nameof(ISemanticVersion)}.{nameof(ISemanticVersion.Build)}", "2.8", DeprecationLevel.PendingRemoval); - return this.Version.PrereleaseTag; - } - } -#endif - /// An optional prerelease tag. public string PrereleaseTag => this.Version.PrereleaseTag; -- cgit From dc0556ff5feead4ced16b82f407b6b271cbb3d30 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 7 Mar 2019 18:19:11 -0500 Subject: fix log level for multiplayer 'received message' logs --- docs/release-notes.md | 1 + src/SMAPI/Framework/SMultiplayer.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 2f01ee93..c10e663d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,7 @@ These changes have not been released yet. * For players: * Fixed Save Backup not pruning old backups if they're uncompressed. * Fixed issues when a farmhand reconnects before the game notices they're disconnected. + * Fixed 'received message' logs shown in non-developer mode. * For modders: * Added `IContentPack.HasFile` method. diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index ffe2320b..382910a0 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -433,7 +433,7 @@ namespace StardewModdingAPI.Framework ModMessageModel model = this.JsonHelper.Deserialise(json); HashSet playerIDs = new HashSet(model.ToPlayerIDs ?? this.GetKnownPlayerIDs()); if (this.Monitor.IsVerbose) - this.Monitor.Log($"Received message: {json}."); + this.Monitor.Log($"Received message: {json}.", LogLevel.Trace); // notify local mods if (playerIDs.Contains(Game1.player.UniqueMultiplayerID)) -- cgit From 332bcfa5a19509352aa417a04a677b5701c16986 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 21 Mar 2019 23:12:26 -0400 Subject: add content pack translations --- docs/release-notes.md | 1 + src/SMAPI/Framework/ContentPack.cs | 7 +++++- src/SMAPI/Framework/IModMetadata.cs | 10 ++++++-- src/SMAPI/Framework/ModLoading/ModMetadata.cs | 12 ++++++++-- src/SMAPI/Framework/SCore.cs | 33 +++++++++++++-------------- src/SMAPI/IContentPack.cs | 3 +++ 6 files changed, 44 insertions(+), 22 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index c10e663d..afcf0066 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,6 +8,7 @@ These changes have not been released yet. * Fixed 'received message' logs shown in non-developer mode. * For modders: + * Added support for content pack translations. * Added `IContentPack.HasFile` method. * Dropped support for all deprecated APIs. * Updated to Json.NET 12.0.1. diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs index 5384d98f..829a7dc1 100644 --- a/src/SMAPI/Framework/ContentPack.cs +++ b/src/SMAPI/Framework/ContentPack.cs @@ -30,6 +30,9 @@ namespace StardewModdingAPI.Framework /// The content pack's manifest. public IManifest Manifest { get; } + /// Provides translations stored in the content pack's i18n folder. See for more info. + public ITranslationHelper Translation { get; } + /********* ** Public methods @@ -38,12 +41,14 @@ namespace StardewModdingAPI.Framework /// The full path to the content pack's folder. /// The content pack's manifest. /// Provides an API for loading content assets. + /// Provides translations stored in the content pack's i18n folder. /// Encapsulates SMAPI's JSON file parsing. - public ContentPack(string directoryPath, IManifest manifest, IContentHelper content, JsonHelper jsonHelper) + public ContentPack(string directoryPath, IManifest manifest, IContentHelper content, ITranslationHelper translation, JsonHelper jsonHelper) { this.DirectoryPath = directoryPath; this.Manifest = manifest; this.Content = content; + this.Translation = translation; this.JsonHelper = jsonHelper; } diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs index 38514959..32870c2a 100644 --- a/src/SMAPI/Framework/IModMetadata.cs +++ b/src/SMAPI/Framework/IModMetadata.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Framework.ModLoading; using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; using StardewModdingAPI.Toolkit.Framework.ModData; @@ -42,6 +43,9 @@ namespace StardewModdingAPI.Framework /// The content pack instance (if loaded and is true). IContentPack ContentPack { get; } + /// The translations for this mod (if loaded). + TranslationHelper Translations { get; } + /// Writes messages to the console and log file as this mod. IMonitor Monitor { get; } @@ -67,12 +71,14 @@ namespace StardewModdingAPI.Framework /// Set the mod instance. /// The mod instance to set. - IModMetadata SetMod(IMod mod); + /// The translations for this mod (if loaded). + IModMetadata SetMod(IMod mod, TranslationHelper translations); /// Set the mod instance. /// The contentPack instance to set. /// Writes messages to the console and log file. - IModMetadata SetMod(IContentPack contentPack, IMonitor monitor); + /// The translations for this mod (if loaded). + IModMetadata SetMod(IContentPack contentPack, IMonitor monitor, TranslationHelper translations); /// Set the mod-provided API instance. /// The mod-provided API. diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index 4ff021b7..39f2f482 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Framework.UpdateData; @@ -46,6 +47,9 @@ namespace StardewModdingAPI.Framework.ModLoading /// The content pack instance (if loaded and is true). public IContentPack ContentPack { get; private set; } + /// The translations for this mod (if loaded). + public TranslationHelper Translations { get; private set; } + /// Writes messages to the console and log file as this mod. public IMonitor Monitor { get; private set; } @@ -100,26 +104,30 @@ namespace StardewModdingAPI.Framework.ModLoading /// Set the mod instance. /// The mod instance to set. - public IModMetadata SetMod(IMod mod) + /// The translations for this mod (if loaded). + public IModMetadata SetMod(IMod mod, TranslationHelper translations) { if (this.ContentPack != null) throw new InvalidOperationException("A mod can't be both an assembly mod and content pack."); this.Mod = mod; this.Monitor = mod.Monitor; + this.Translations = translations; return this; } /// Set the mod instance. /// The contentPack instance to set. /// Writes messages to the console and log file. - public IModMetadata SetMod(IContentPack contentPack, IMonitor monitor) + /// The translations for this mod (if loaded). + public IModMetadata SetMod(IContentPack contentPack, IMonitor monitor, TranslationHelper translations) { if (this.Mod != null) throw new InvalidOperationException("A mod can't be both an assembly mod and content pack."); this.ContentPack = contentPack; this.Monitor = monitor; + this.Translations = translations; return this; } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 06a2e0af..2f0e0f05 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -427,8 +427,8 @@ namespace StardewModdingAPI.Framework LocalizedContentManager.LanguageCode languageCode = this.ContentCore.Language; // update mod translation helpers - foreach (IModMetadata mod in this.ModRegistry.GetAll(contentPacks: false)) - (mod.Mod.Helper.Translation as TranslationHelper)?.SetLocale(locale, languageCode); + foreach (IModMetadata mod in this.ModRegistry.GetAll()) + mod.Translations.SetLocale(locale, languageCode); } /// Run a loop handling console input. @@ -725,8 +725,9 @@ namespace StardewModdingAPI.Framework LogSkip(contentPack, errorPhrase, errorDetails); } } - IModMetadata[] loadedContentPacks = this.ModRegistry.GetAll(assemblyMods: false).ToArray(); - IModMetadata[] loadedMods = this.ModRegistry.GetAll(contentPacks: false).ToArray(); + IModMetadata[] loaded = this.ModRegistry.GetAll().ToArray(); + IModMetadata[] loadedContentPacks = loaded.Where(p => p.IsContentPack).ToArray(); + IModMetadata[] loadedMods = loaded.Where(p => !p.IsContentPack).ToArray(); // unlock content packs this.ModRegistry.AreAllModsLoaded = true; @@ -766,10 +767,10 @@ namespace StardewModdingAPI.Framework } // log mod warnings - this.LogModWarnings(this.ModRegistry.GetAll().ToArray(), skippedMods); + this.LogModWarnings(loaded, skippedMods); // initialise translations - this.ReloadTranslations(loadedMods); + this.ReloadTranslations(loaded); // initialise loaded non-content-pack mods foreach (IModMetadata metadata in loadedMods) @@ -919,8 +920,9 @@ namespace StardewModdingAPI.Framework IManifest manifest = mod.Manifest; IMonitor monitor = this.GetSecondaryMonitor(mod.DisplayName); IContentHelper contentHelper = new ContentHelper(this.ContentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, monitor); - IContentPack contentPack = new ContentPack(mod.DirectoryPath, manifest, contentHelper, jsonHelper); - mod.SetMod(contentPack, monitor); + TranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, manifest.Name, contentCore.GetLocale(), contentCore.Language); + IContentPack contentPack = new ContentPack(mod.DirectoryPath, manifest, contentHelper, translationHelper, jsonHelper); + mod.SetMod(contentPack, monitor, translationHelper); this.ModRegistry.Add(mod); errorReasonPhrase = null; @@ -982,6 +984,7 @@ namespace StardewModdingAPI.Framework // init mod helpers IMonitor monitor = this.GetSecondaryMonitor(mod.DisplayName); + TranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, manifest.Name, contentCore.GetLocale(), contentCore.Language); IModHelper modHelper; { IModEvents events = new ModEvents(mod, this.EventManager); @@ -992,13 +995,13 @@ namespace StardewModdingAPI.Framework IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, mod.DisplayName, this.Reflection); IModRegistry modRegistryHelper = new ModRegistryHelper(manifest.UniqueID, this.ModRegistry, proxyFactory, monitor); IMultiplayerHelper multiplayerHelper = new MultiplayerHelper(manifest.UniqueID, this.GameInstance.Multiplayer); - ITranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, manifest.Name, contentCore.GetLocale(), contentCore.Language); IContentPack CreateFakeContentPack(string packDirPath, IManifest packManifest) { IMonitor packMonitor = this.GetSecondaryMonitor(packManifest.Name); IContentHelper packContentHelper = new ContentHelper(contentCore, packDirPath, packManifest.UniqueID, packManifest.Name, packMonitor); - return new ContentPack(packDirPath, packManifest, packContentHelper, this.Toolkit.JsonHelper); + ITranslationHelper packTranslationHelper = new TranslationHelper(packManifest.UniqueID, packManifest.Name, contentCore.GetLocale(), contentCore.Language); + return new ContentPack(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper); } modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.GameInstance.Input, events, contentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper); @@ -1010,7 +1013,7 @@ namespace StardewModdingAPI.Framework modEntry.Monitor = monitor; // track mod - mod.SetMod(modEntry); + mod.SetMod(modEntry, translationHelper); this.ModRegistry.Add(mod); return true; } @@ -1025,7 +1028,7 @@ namespace StardewModdingAPI.Framework /// Write a summary of mod warnings to the console and log. /// The loaded mods. /// The mods which were skipped, along with the friendly and developer reasons. - private void LogModWarnings(IModMetadata[] mods, IDictionary> skippedMods) + private void LogModWarnings(IEnumerable mods, IDictionary> skippedMods) { // get mods with warnings IModMetadata[] modsWithWarnings = mods.Where(p => p.Warnings != ModWarning.None).ToArray(); @@ -1165,9 +1168,6 @@ namespace StardewModdingAPI.Framework JsonHelper jsonHelper = this.Toolkit.JsonHelper; foreach (IModMetadata metadata in mods) { - if (metadata.IsContentPack) - throw new InvalidOperationException("Can't reload translations for a content pack."); - // read translation files IDictionary> translations = new Dictionary>(); DirectoryInfo translationsDir = new DirectoryInfo(Path.Combine(metadata.DirectoryPath, "i18n")); @@ -1217,8 +1217,7 @@ namespace StardewModdingAPI.Framework } // update translation - TranslationHelper translationHelper = (TranslationHelper)metadata.Mod.Helper.Translation; - translationHelper.SetTranslations(translations); + metadata.Translations.SetTranslations(translations); } } diff --git a/src/SMAPI/IContentPack.cs b/src/SMAPI/IContentPack.cs index 32cbc6fc..7085c538 100644 --- a/src/SMAPI/IContentPack.cs +++ b/src/SMAPI/IContentPack.cs @@ -17,6 +17,9 @@ namespace StardewModdingAPI /// The content pack's manifest. IManifest Manifest { get; } + /// Provides translations stored in the content pack's i18n folder. See for more info. + ITranslationHelper Translation { get; } + /********* ** Public methods -- cgit From f78502a3a4a133b93cf9bf01eb426867e7798045 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 21 Mar 2019 23:14:31 -0400 Subject: fix incorrect input check, update release notes --- docs/release-notes.md | 1 + src/SMAPI/Framework/Input/SInputState.cs | 3 +++ 2 files changed, 4 insertions(+) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index afcf0066..4fb7b6c3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,7 @@ These changes have not been released yet. * For players: + * Improved performance. * Fixed Save Backup not pruning old backups if they're uncompressed. * Fixed issues when a farmhand reconnects before the game notices they're disconnected. * Fixed 'received message' logs shown in non-developer mode. diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs index 96a7003a..a15272d5 100644 --- a/src/SMAPI/Framework/Input/SInputState.cs +++ b/src/SMAPI/Framework/Input/SInputState.cs @@ -94,7 +94,10 @@ namespace StardewModdingAPI.Framework.Input this.RealKeyboard = realKeyboard; this.RealMouse = realMouse; if (cursorAbsolutePos != this.CursorPositionImpl?.AbsolutePixels || playerTilePos != this.LastPlayerTile) + { + this.LastPlayerTile = playerTilePos; this.CursorPositionImpl = this.GetCursorPosition(realMouse, cursorAbsolutePos); + } // update suppressed states this.SuppressButtons.RemoveWhere(p => !this.GetStatus(activeButtons, p).IsDown()); -- cgit From 4689eeb6a3af1aead00347fc2575bfebdee50113 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 30 Mar 2019 01:25:12 -0400 Subject: load mods much earlier so they can intercept all content assets --- docs/release-notes.md | 2 + src/SMAPI/Context.cs | 3 ++ src/SMAPI/Framework/ContentCoordinator.cs | 11 ++-- .../ContentManagers/GameContentManager.cs | 17 +++++- src/SMAPI/Framework/SCore.cs | 62 ++++++++++++++-------- src/SMAPI/Framework/SGame.cs | 9 +++- src/SMAPI/Framework/SGameConstructorHack.cs | 8 ++- 7 files changed, 85 insertions(+), 27 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 4fb7b6c3..649cd774 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -11,6 +11,8 @@ These changes have not been released yet. * For modders: * Added support for content pack translations. * Added `IContentPack.HasFile` method. + * Added `Context.IsGameLaunched` field. + * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised). * Dropped support for all deprecated APIs. * Updated to Json.NET 12.0.1. diff --git a/src/SMAPI/Context.cs b/src/SMAPI/Context.cs index 1cdef7f1..a933752d 100644 --- a/src/SMAPI/Context.cs +++ b/src/SMAPI/Context.cs @@ -14,6 +14,9 @@ namespace StardewModdingAPI /**** ** Public ****/ + /// Whether the game has performed core initialisation. This becomes true right before the first update tick.. + public static bool IsGameLaunched { get; internal set; } + /// Whether the player has loaded a save and the world has finished initialising. public static bool IsWorldReady { get; internal set; } diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index ee654081..caeb7ee9 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -36,6 +36,9 @@ namespace StardewModdingAPI.Framework /// Encapsulates SMAPI's JSON file parsing. private readonly JsonHelper JsonHelper; + /// A callback to invoke the first time *any* game content manager loads an asset. + private readonly Action OnLoadingFirstAsset; + /// The loaded content managers (including the ). private readonly IList ContentManagers = new List(); @@ -72,14 +75,16 @@ namespace StardewModdingAPI.Framework /// Encapsulates monitoring and logging. /// Simplifies access to private code. /// Encapsulates SMAPI's JSON file parsing. - public ContentCoordinator(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper) + /// A callback to invoke the first time *any* game content manager loads an asset. + public ContentCoordinator(IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onLoadingFirstAsset) { this.Monitor = monitor ?? throw new ArgumentNullException(nameof(monitor)); this.Reflection = reflection; this.JsonHelper = jsonHelper; + this.OnLoadingFirstAsset = onLoadingFirstAsset; this.FullRootDirectory = Path.Combine(Constants.ExecutionPath, rootDirectory); this.ContentManagers.Add( - this.MainContentManager = new GameContentManager("Game1.content", serviceProvider, rootDirectory, currentCulture, this, monitor, reflection, this.OnDisposing) + this.MainContentManager = new GameContentManager("Game1.content", serviceProvider, rootDirectory, currentCulture, this, monitor, reflection, this.OnDisposing, onLoadingFirstAsset) ); this.CoreAssets = new CoreAssetPropagator(this.MainContentManager.AssertAndNormaliseAssetName, reflection, monitor); } @@ -88,7 +93,7 @@ namespace StardewModdingAPI.Framework /// A name for the mod manager. Not guaranteed to be unique. public GameContentManager CreateGameContentManager(string name) { - GameContentManager manager = new GameContentManager(name, this.MainContentManager.ServiceProvider, this.MainContentManager.RootDirectory, this.MainContentManager.CurrentCulture, this, this.Monitor, this.Reflection, this.OnDisposing); + GameContentManager manager = new GameContentManager(name, this.MainContentManager.ServiceProvider, this.MainContentManager.RootDirectory, this.MainContentManager.CurrentCulture, this, this.Monitor, this.Reflection, this.OnDisposing, this.OnLoadingFirstAsset); this.ContentManagers.Add(manager); return manager; } diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index ee940cc7..f159f035 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -28,6 +28,12 @@ namespace StardewModdingAPI.Framework.ContentManagers /// A lookup which indicates whether the asset is localisable (i.e. the filename contains the locale), if previously loaded. private readonly IDictionary IsLocalisableLookup; + /// Whether the next load is the first for any game content manager. + private static bool IsFirstLoad = true; + + /// A callback to invoke the first time *any* game content manager loads an asset. + private readonly Action OnLoadingFirstAsset; + /********* ** Public methods @@ -41,10 +47,12 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Encapsulates monitoring and logging. /// Simplifies access to private code. /// A callback to invoke when the content manager is being disposed. - public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action onDisposing) + /// A callback to invoke the first time *any* game content manager loads an asset. + public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action onDisposing, Action onLoadingFirstAsset) : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isModFolder: false) { this.IsLocalisableLookup = reflection.GetField>(this, "_localizedAsset").GetValue(); + this.OnLoadingFirstAsset = onLoadingFirstAsset; } /// Load an asset that has been processed by the content pipeline. @@ -53,6 +61,13 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The language code for which to load content. public override T Load(string assetName, LanguageCode language) { + // raise first-load callback + if (GameContentManager.IsFirstLoad) + { + GameContentManager.IsFirstLoad = false; + this.OnLoadingFirstAsset(); + } + // normalise asset name assetName = this.AssertAndNormaliseAssetName(assetName); if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage)) diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 2f0e0f05..f64af82b 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -209,8 +209,19 @@ namespace StardewModdingAPI.Framework AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => AssemblyLoader.ResolveAssembly(e.Name); // override game - SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper); - this.GameInstance = new SGame(this.Monitor, this.MonitorForGame, this.Reflection, this.EventManager, this.Toolkit.JsonHelper, this.ModRegistry, SCore.DeprecationManager, this.OnLocaleChanged, this.InitialiseAfterGameStart, this.Dispose); + SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper, this.InitialiseBeforeFirstAssetLoaded); + this.GameInstance = new SGame( + monitor: this.Monitor, + monitorForGame: this.MonitorForGame, + reflection: this.Reflection, + eventManager: this.EventManager, + jsonHelper: this.Toolkit.JsonHelper, + modRegistry: this.ModRegistry, + deprecationManager: SCore.DeprecationManager, + onLocaleChanged: this.OnLocaleChanged, + onGameInitialised: this.InitialiseAfterGameStart, + onGameExiting: this.Dispose + ); StardewValley.Program.gamePtr = this.GameInstance; // apply game patches @@ -280,6 +291,19 @@ namespace StardewModdingAPI.Framework File.Delete(Constants.FatalCrashMarker); } + // add headers + if (this.Settings.DeveloperMode) + this.Monitor.Log($"You have SMAPI for developers, so the console will be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info); + if (!this.Settings.CheckForUpdates) + this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn); + if (!this.Monitor.WriteToConsole) + this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn); + this.Monitor.VerboseLog("Verbose logging enabled."); + + // update window titles + this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion}"; + Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion}"; + // start game this.Monitor.Log("Starting game...", LogLevel.Debug); try @@ -349,21 +373,14 @@ namespace StardewModdingAPI.Framework /********* ** Private methods *********/ - /// Initialise SMAPI and mods after the game starts. - private void InitialiseAfterGameStart() + /// Initialise mods before the first game asset is loaded. At this point the core content managers are loaded (so mods can load their own assets), but the game is mostly uninitialised. + private void InitialiseBeforeFirstAssetLoaded() { - // add headers - if (this.Settings.DeveloperMode) - this.Monitor.Log($"You have SMAPI for developers, so the console will be much more verbose. You can disable developer mode by installing the non-developer version of SMAPI, or by editing {Constants.ApiConfigPath}.", LogLevel.Info); - if (!this.Settings.CheckForUpdates) - this.Monitor.Log($"You configured SMAPI to not check for updates. Running an old version of SMAPI is not recommended. You can enable update checks by reinstalling SMAPI or editing {Constants.ApiConfigPath}.", LogLevel.Warn); - if (!this.Monitor.WriteToConsole) - this.Monitor.Log("Writing to the terminal is disabled because the --no-terminal argument was received. This usually means launching the terminal failed.", LogLevel.Warn); - this.Monitor.VerboseLog("Verbose logging enabled."); - - // validate XNB integrity - if (!this.ValidateContentIntegrity()) - this.Monitor.Log("SMAPI found problems in your game's content files which are likely to cause errors or crashes. Consider uninstalling XNB mods or reinstalling the game.", LogLevel.Error); + if (this.Monitor.IsExiting) + { + this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn); + return; + } // load mod data ModToolkit toolkit = new ModToolkit(); @@ -404,16 +421,19 @@ namespace StardewModdingAPI.Framework // check for updates this.CheckForUpdatesAsync(mods); } - if (this.Monitor.IsExiting) - { - this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn); - return; - } // update window titles int modsLoaded = this.ModRegistry.GetAll().Count(); this.GameInstance.Window.Title = $"Stardew Valley {Constants.GameVersion} - running SMAPI {Constants.ApiVersion} with {modsLoaded} mods"; Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion} with {modsLoaded} mods"; + } + + /// Initialise SMAPI and mods after the game starts. + private void InitialiseAfterGameStart() + { + // validate XNB integrity + if (!this.ValidateContentIntegrity()) + this.Monitor.Log("SMAPI found problems in your game's content files which are likely to cause errors or crashes. Consider uninstalling XNB mods or reinstalling the game.", LogLevel.Error); // start SMAPI console new Thread(this.RunConsoleLoop).Start(); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index b35e1d71..002a5d1b 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -75,6 +75,9 @@ namespace StardewModdingAPI.Framework /// A callback to invoke after the content language changes. private readonly Action OnLocaleChanged; + /// A callback to invoke the first time *any* game content manager loads an asset. + private readonly Action OnLoadingFirstAsset; + /// A callback to invoke after the game finishes initialising. private readonly Action OnGameInitialised; @@ -139,6 +142,7 @@ namespace StardewModdingAPI.Framework /// A callback to invoke when the game exits. internal SGame(IMonitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onLocaleChanged, Action onGameInitialised, Action onGameExiting) { + this.OnLoadingFirstAsset = SGame.ConstructorHack.OnLoadingFirstAsset; SGame.ConstructorHack = null; // check expectations @@ -237,7 +241,7 @@ namespace StardewModdingAPI.Framework // NOTE: this method is called before the SGame constructor runs. Don't depend on anything being initialised at this point. if (this.ContentCore == null) { - this.ContentCore = new ContentCoordinator(serviceProvider, rootDirectory, Thread.CurrentThread.CurrentUICulture, SGame.ConstructorHack.Monitor, SGame.ConstructorHack.Reflection, SGame.ConstructorHack.JsonHelper); + this.ContentCore = new ContentCoordinator(serviceProvider, rootDirectory, Thread.CurrentThread.CurrentUICulture, SGame.ConstructorHack.Monitor, SGame.ConstructorHack.Reflection, SGame.ConstructorHack.JsonHelper, this.OnLoadingFirstAsset ?? SGame.ConstructorHack?.OnLoadingFirstAsset); this.NextContentManagerIsMain = true; return this.ContentCore.CreateGameContentManager("Game1._temporaryContent"); } @@ -764,7 +768,10 @@ namespace StardewModdingAPI.Framework // game launched bool isFirstTick = SGame.TicksElapsed == 0; if (isFirstTick) + { + Context.IsGameLaunched = true; events.GameLaunched.Raise(new GameLaunchedEventArgs()); + } // preloaded if (Context.IsSaveLoaded && Context.LoadStage != LoadStage.Loaded && Context.LoadStage != LoadStage.Ready) diff --git a/src/SMAPI/Framework/SGameConstructorHack.cs b/src/SMAPI/Framework/SGameConstructorHack.cs index 494bab99..c3d22197 100644 --- a/src/SMAPI/Framework/SGameConstructorHack.cs +++ b/src/SMAPI/Framework/SGameConstructorHack.cs @@ -1,3 +1,4 @@ +using System; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Toolkit.Serialisation; using StardewValley; @@ -19,6 +20,9 @@ namespace StardewModdingAPI.Framework /// Encapsulates SMAPI's JSON file parsing. public JsonHelper JsonHelper { get; } + /// A callback to invoke the first time *any* game content manager loads an asset. + public Action OnLoadingFirstAsset { get; } + /********* ** Public methods @@ -27,11 +31,13 @@ namespace StardewModdingAPI.Framework /// Encapsulates monitoring and logging. /// Simplifies access to private game code. /// Encapsulates SMAPI's JSON file parsing. - public SGameConstructorHack(IMonitor monitor, Reflector reflection, JsonHelper jsonHelper) + /// A callback to invoke the first time *any* game content manager loads an asset. + public SGameConstructorHack(IMonitor monitor, Reflector reflection, JsonHelper jsonHelper, Action onLoadingFirstAsset) { this.Monitor = monitor; this.Reflection = reflection; this.JsonHelper = jsonHelper; + this.OnLoadingFirstAsset = onLoadingFirstAsset; } } } -- cgit From 307055b028e0d6643983189e96a5ebcbe89d32ba Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 4 Apr 2019 18:43:56 -0400 Subject: bump version to 3.0 --- build/GlobalAssemblyInfo.cs | 4 ++-- src/SMAPI.Mods.ConsoleCommands/manifest.json | 4 ++-- src/SMAPI.Mods.SaveBackup/manifest.json | 4 ++-- src/SMAPI/Constants.cs | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/SMAPI') diff --git a/build/GlobalAssemblyInfo.cs b/build/GlobalAssemblyInfo.cs index a3ca3051..0fa0d331 100644 --- a/build/GlobalAssemblyInfo.cs +++ b/build/GlobalAssemblyInfo.cs @@ -1,5 +1,5 @@ using System.Reflection; [assembly: AssemblyProduct("SMAPI")] -[assembly: AssemblyVersion("2.11.3")] -[assembly: AssemblyFileVersion("2.11.3")] +[assembly: AssemblyVersion("3.0.0")] +[assembly: AssemblyFileVersion("3.0.0")] diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 74295410..802de3a6 100644 --- a/src/SMAPI.Mods.ConsoleCommands/manifest.json +++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json @@ -1,9 +1,9 @@ { "Name": "Console Commands", "Author": "SMAPI", - "Version": "2.11.3", + "Version": "3.0.0", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "2.11.3" + "MinimumApiVersion": "3.0.0" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index e147bd39..eddd3443 100644 --- a/src/SMAPI.Mods.SaveBackup/manifest.json +++ b/src/SMAPI.Mods.SaveBackup/manifest.json @@ -1,9 +1,9 @@ { "Name": "Save Backup", "Author": "SMAPI", - "Version": "2.11.3", + "Version": "3.0.0", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "2.11.3" + "MinimumApiVersion": "3.0.0" } diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 736a10ea..3ba3e6dd 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -20,13 +20,13 @@ namespace StardewModdingAPI ** Public ****/ /// SMAPI's current semantic version. - public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("2.11.3"); + public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.0.0"); /// The minimum supported version of Stardew Valley. - public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.36"); + public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.4.0"); /// The maximum supported version of Stardew Valley. - public static ISemanticVersion MaximumGameVersion { get; } = new GameVersion("1.3.36"); + public static ISemanticVersion MaximumGameVersion { get; } = null; /// The target game platform. public static GamePlatform TargetPlatform => (GamePlatform)Constants.Platform; -- cgit From 09d1c5a601e77c051dfde8a31f422b2c898086c3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 6 Apr 2019 00:35:53 -0400 Subject: list all detected issues in trace logs for incompatible mods --- docs/release-notes.md | 1 + src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 20 +++++++++---------- .../ReferenceToMemberWithUnexpectedTypeFinder.cs | 5 +---- .../ModLoading/IncompatibleInstructionException.cs | 23 ++++------------------ 4 files changed, 16 insertions(+), 33 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index e9819860..6aa3c024 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -14,6 +14,7 @@ These changes have not been released yet. * Added `IContentPack.HasFile` method. * Added `Context.IsGameLaunched` field. * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised). + * When a mod is incompatible, the trace logs now list all detected issues instead of the first one. * Dropped support for all deprecated APIs. * Updated to Json.NET 12.0.1. diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 878b3148..ca171ae1 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -105,7 +105,7 @@ namespace StardewModdingAPI.Framework.ModLoading continue; // rewrite assembly - bool changed = this.RewriteAssembly(mod, assembly.Definition, assumeCompatible, loggedMessages, logPrefix: " "); + bool changed = this.RewriteAssembly(mod, assembly.Definition, loggedMessages, logPrefix: " "); // detect broken assembly reference foreach (AssemblyNameReference reference in assembly.Definition.MainModule.AssemblyReferences) @@ -114,7 +114,7 @@ namespace StardewModdingAPI.Framework.ModLoading { this.Monitor.LogOnce(loggedMessages, $" Broken code in {assembly.File.Name}: reference to missing assembly '{reference.FullName}'."); if (!assumeCompatible) - throw new IncompatibleInstructionException($"assembly reference to {reference.FullName}", $"Found a reference to missing assembly '{reference.FullName}' while loading assembly {assembly.File.Name}."); + throw new IncompatibleInstructionException($"Found a reference to missing assembly '{reference.FullName}' while loading assembly {assembly.File.Name}."); mod.SetWarning(ModWarning.BrokenCodeLoaded); break; } @@ -143,6 +143,10 @@ namespace StardewModdingAPI.Framework.ModLoading this.AssemblyDefinitionResolver.Add(assembly.Definition); } + // throw if incompatibilities detected + if (!assumeCompatible && mod.Warnings.HasFlag(ModWarning.BrokenCodeLoaded)) + throw new IncompatibleInstructionException(); + // last assembly loaded is the root return lastAssembly; } @@ -244,12 +248,11 @@ namespace StardewModdingAPI.Framework.ModLoading /// Rewrite the types referenced by an assembly. /// The mod for which the assembly is being loaded. /// The assembly to rewrite. - /// Assume the mod is compatible, even if incompatible code is detected. /// The messages that have already been logged for this mod. /// A string to prefix to log messages. /// Returns whether the assembly was modified. /// An incompatible CIL instruction was found while rewriting the assembly. - private bool RewriteAssembly(IModMetadata mod, AssemblyDefinition assembly, bool assumeCompatible, HashSet loggedMessages, string logPrefix) + private bool RewriteAssembly(IModMetadata mod, AssemblyDefinition assembly, HashSet loggedMessages, string logPrefix) { ModuleDefinition module = assembly.MainModule; string filename = $"{assembly.Name.Name}.dll"; @@ -288,7 +291,7 @@ namespace StardewModdingAPI.Framework.ModLoading foreach (IInstructionHandler handler in handlers) { InstructionHandleResult result = handler.Handle(module, method, this.AssemblyMap, platformChanged); - this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, assumeCompatible, filename); + this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, filename); if (result == InstructionHandleResult.Rewritten) anyRewritten = true; } @@ -303,7 +306,7 @@ namespace StardewModdingAPI.Framework.ModLoading { Instruction instruction = instructions[offset]; InstructionHandleResult result = handler.Handle(module, cil, instruction, this.AssemblyMap, platformChanged); - this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, assumeCompatible, filename); + this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, filename); if (result == InstructionHandleResult.Rewritten) anyRewritten = true; } @@ -318,10 +321,9 @@ namespace StardewModdingAPI.Framework.ModLoading /// The instruction handler. /// The result returned by the handler. /// The messages already logged for the current mod. - /// Assume the mod is compatible, even if incompatible code is detected. /// A string to prefix to log messages. /// The assembly filename for log messages. - private void ProcessInstructionHandleResult(IModMetadata mod, IInstructionHandler handler, InstructionHandleResult result, HashSet loggedMessages, string logPrefix, bool assumeCompatible, string filename) + private void ProcessInstructionHandleResult(IModMetadata mod, IInstructionHandler handler, InstructionHandleResult result, HashSet loggedMessages, string logPrefix, string filename) { switch (result) { @@ -331,8 +333,6 @@ namespace StardewModdingAPI.Framework.ModLoading case InstructionHandleResult.NotCompatible: this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Broken code in {filename}: {handler.NounPhrase}."); - if (!assumeCompatible) - throw new IncompatibleInstructionException(handler.NounPhrase, $"Found an incompatible CIL instruction ({handler.NounPhrase}) while loading assembly {filename}."); mod.SetWarning(ModWarning.BrokenCodeLoaded); break; diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs index 82c4920a..459e3210 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs @@ -80,10 +80,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders // compare return types MethodDefinition methodDef = methodReference.Resolve(); if (methodDef == null) - { - this.NounPhrase = $"reference to {methodReference.DeclaringType.FullName}.{methodReference.Name} (no such method)"; - return InstructionHandleResult.NotCompatible; - } + return InstructionHandleResult.None; // validated by ReferenceToMissingMemberFinder if (candidateMethods.All(method => !RewriteHelper.LooksLikeSameType(method.ReturnType, methodDef.ReturnType))) { diff --git a/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs b/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs index 17ec24b1..1f9add30 100644 --- a/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs +++ b/src/SMAPI/Framework/ModLoading/IncompatibleInstructionException.cs @@ -5,31 +5,16 @@ namespace StardewModdingAPI.Framework.ModLoading /// An exception raised when an incompatible instruction is found while loading a mod assembly. internal class IncompatibleInstructionException : Exception { - /********* - ** Accessors - *********/ - /// A brief noun phrase which describes the incompatible instruction that was found. - public string NounPhrase { get; } - - /********* ** Public methods *********/ /// Construct an instance. - /// A brief noun phrase which describes the incompatible instruction that was found. - public IncompatibleInstructionException(string nounPhrase) - : base($"Found an incompatible CIL instruction ({nounPhrase}).") - { - this.NounPhrase = nounPhrase; - } + public IncompatibleInstructionException() + : base("Found incompatible CIL instructions.") { } /// Construct an instance. - /// A brief noun phrase which describes the incompatible instruction that was found. /// A message which describes the error. - public IncompatibleInstructionException(string nounPhrase, string message) - : base(message) - { - this.NounPhrase = nounPhrase; - } + public IncompatibleInstructionException(string message) + : base(message) { } } } -- cgit From 6c220453e16c6cb5ad150b61cf02685a97557b3c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 15 Apr 2019 00:40:45 -0400 Subject: fix translatable assets not updated when switching language (#586) --- docs/release-notes.md | 1 + src/SMAPI/Framework/ContentCoordinator.cs | 7 +++++++ .../ContentManagers/BaseContentManager.cs | 3 +++ .../ContentManagers/GameContentManager.cs | 23 ++++++++++++++++++++++ .../Framework/ContentManagers/IContentManager.cs | 3 +++ src/SMAPI/Framework/SCore.cs | 6 +++++- src/SMAPI/Framework/SGame.cs | 8 +------- 7 files changed, 43 insertions(+), 8 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 6aa3c024..84738ff7 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,6 +8,7 @@ These changes have not been released yet. * Fixed Save Backup not pruning old backups if they're uncompressed. * Fixed issues when a farmhand reconnects before the game notices they're disconnected. * Fixed 'received message' logs shown in non-developer mode. + * Fixed some assets not updated when you switch language to English. * For modders: * Added support for content pack translations. diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index caeb7ee9..25eeb2ef 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -114,6 +114,13 @@ namespace StardewModdingAPI.Framework return this.MainContentManager.GetLocale(LocalizedContentManager.CurrentLanguageCode); } + /// Perform any cleanup needed when the locale changes. + public void OnLocaleChanged() + { + foreach (IContentManager contentManager in this.ContentManagers) + contentManager.OnLocaleChanged(); + } + /// Get whether this asset is mapped to a mod folder. /// The asset key. public bool IsManagedAssetKey(string key) diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs index 7821e454..b2b3769b 100644 --- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs @@ -138,6 +138,9 @@ namespace StardewModdingAPI.Framework.ContentManagers } } + /// Perform any cleanup needed when the locale changes. + public virtual void OnLocaleChanged() { } + /// Normalise path separators in a file path. For asset keys, see instead. /// The file path to normalise. [Pure] diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index f159f035..55cf15ec 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -112,6 +112,29 @@ namespace StardewModdingAPI.Framework.ContentManagers return data; } + /// Perform any cleanup needed when the locale changes. + public override void OnLocaleChanged() + { + base.OnLocaleChanged(); + + // find assets for which a translatable version was loaded + HashSet removeAssetNames = new HashSet(StringComparer.InvariantCultureIgnoreCase); + foreach (string key in this.IsLocalisableLookup.Where(p => p.Value).Select(p => p.Key)) + removeAssetNames.Add(this.TryParseExplicitLanguageAssetKey(key, out string assetName, out _) ? assetName : key); + + // invalidate translatable assets + string[] invalidated = this + .InvalidateCache((key, type) => + removeAssetNames.Contains(key) + || (this.TryParseExplicitLanguageAssetKey(key, out string assetName, out _) && removeAssetNames.Contains(assetName)) + ) + .Select(p => p.Item1) + .OrderBy(p => p, StringComparer.InvariantCultureIgnoreCase) + .ToArray(); + if (invalidated.Any()) + this.Monitor.Log($"Invalidated {invalidated.Length} asset names: {string.Join(", ", invalidated)} for locale change.", LogLevel.Trace); + } + /// Create a new content manager for temporary use. public override LocalizedContentManager CreateTemporary() { diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs index 17618edd..66ef9181 100644 --- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs @@ -52,6 +52,9 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The asset to clone. T CloneIfPossible(T asset); + /// Perform any cleanup needed when the locale changes. + void OnLocaleChanged(); + /// Normalise path separators in a file path. For asset keys, see instead. /// The file path to normalise. [Pure] diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index f64af82b..e8d5b672 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -208,6 +208,9 @@ namespace StardewModdingAPI.Framework // add more leniant assembly resolvers AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => AssemblyLoader.ResolveAssembly(e.Name); + // hook locale event + LocalizedContentManager.OnLanguageChange += locale => this.OnLocaleChanged(); + // override game SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper, this.InitialiseBeforeFirstAssetLoaded); this.GameInstance = new SGame( @@ -218,7 +221,6 @@ namespace StardewModdingAPI.Framework jsonHelper: this.Toolkit.JsonHelper, modRegistry: this.ModRegistry, deprecationManager: SCore.DeprecationManager, - onLocaleChanged: this.OnLocaleChanged, onGameInitialised: this.InitialiseAfterGameStart, onGameExiting: this.Dispose ); @@ -442,6 +444,8 @@ namespace StardewModdingAPI.Framework /// Handle the game changing locale. private void OnLocaleChanged() { + this.ContentCore.OnLocaleChanged(); + // get locale string locale = this.ContentCore.GetLocale(); LocalizedContentManager.LanguageCode languageCode = this.ContentCore.Language; diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 002a5d1b..684ff3ba 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -72,9 +72,6 @@ namespace StardewModdingAPI.Framework /// Whether the game is creating the save file and SMAPI has already raised . private bool IsBetweenCreateEvents; - /// A callback to invoke after the content language changes. - private readonly Action OnLocaleChanged; - /// A callback to invoke the first time *any* game content manager loads an asset. private readonly Action OnLoadingFirstAsset; @@ -137,10 +134,9 @@ namespace StardewModdingAPI.Framework /// Encapsulates SMAPI's JSON file parsing. /// Tracks the installed mods. /// Manages deprecation warnings. - /// A callback to invoke after the content language changes. /// A callback to invoke after the game finishes initialising. /// A callback to invoke when the game exits. - internal SGame(IMonitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onLocaleChanged, Action onGameInitialised, Action onGameExiting) + internal SGame(IMonitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialised, Action onGameExiting) { this.OnLoadingFirstAsset = SGame.ConstructorHack.OnLoadingFirstAsset; SGame.ConstructorHack = null; @@ -159,7 +155,6 @@ namespace StardewModdingAPI.Framework this.ModRegistry = modRegistry; this.Reflection = reflection; this.DeprecationManager = deprecationManager; - this.OnLocaleChanged = onLocaleChanged; this.OnGameInitialised = onGameInitialised; this.OnGameExiting = onGameExiting; Game1.input = new SInputState(); @@ -467,7 +462,6 @@ namespace StardewModdingAPI.Framework if (this.Watchers.LocaleWatcher.IsChanged) { this.Monitor.Log($"Context: locale set to {this.Watchers.LocaleWatcher.CurrentValue}.", LogLevel.Trace); - this.OnLocaleChanged(); this.Watchers.LocaleWatcher.Reset(); } -- cgit From 161618d0d92bad5b31e2780c8899c73339d38b62 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 15 Apr 2019 21:45:27 -0400 Subject: fix cache miss when not playing in English (#634) --- .../ContentManagers/BaseContentManager.cs | 4 +-- .../ContentManagers/GameContentManager.cs | 30 ++++++++++++++++++---- .../Framework/ContentManagers/IContentManager.cs | 5 ++-- .../Framework/ContentManagers/ModContentManager.cs | 4 +-- src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 2 +- 5 files changed, 32 insertions(+), 13 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs index b2b3769b..f54262b8 100644 --- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs @@ -103,11 +103,11 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The type of asset to inject. /// The asset path relative to the loader root directory, not including the .xnb extension. /// The asset value. - public void Inject(string assetName, T value) + /// The language code for which to inject the asset. + public virtual void Inject(string assetName, T value, LanguageCode language) { assetName = this.AssertAndNormaliseAssetName(assetName); this.Cache[assetName] = value; - } /// Get a copy of the given asset if supported. diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 55cf15ec..6ce50f00 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -81,7 +81,7 @@ namespace StardewModdingAPI.Framework.ContentManagers if (this.Coordinator.TryParseManagedAssetKey(assetName, out string contentManagerID, out string relativePath)) { T managedAsset = this.Coordinator.LoadAndCloneManagedAsset(assetName, contentManagerID, relativePath, language); - this.Inject(assetName, managedAsset); + this.Inject(assetName, managedAsset, language); return managedAsset; } @@ -108,10 +108,30 @@ namespace StardewModdingAPI.Framework.ContentManagers } // update cache & return data - this.Inject(assetName, data); + this.Inject(assetName, data, language); return data; } + /// Inject an asset into the cache. + /// The type of asset to inject. + /// The asset path relative to the loader root directory, not including the .xnb extension. + /// The asset value. + /// The language code for which to inject the asset. + public override void Inject(string assetName, T value, LanguageCode language) + { + base.Inject(assetName, value, language); + + // track whether the injected asset is translatable for is-loaded lookups + bool isTranslated = this.TryParseExplicitLanguageAssetKey(assetName, out _, out _); + string localisedKey = isTranslated ? assetName : $"{assetName}.{language}"; + if (this.Cache.ContainsKey(localisedKey)) + this.IsLocalisableLookup[localisedKey] = true; + else if (!isTranslated && this.Cache.ContainsKey(assetName)) + this.IsLocalisableLookup[localisedKey] = false; + else + this.Monitor.Log($"Asset '{assetName}' could not be found in the cache immediately after injection.", LogLevel.Error); + } + /// Perform any cleanup needed when the locale changes. public override void OnLocaleChanged() { @@ -154,11 +174,11 @@ namespace StardewModdingAPI.Framework.ContentManagers return this.Cache.ContainsKey(normalisedAssetName); // translated - string localeKey = $"{normalisedAssetName}.{this.GetLocale(this.GetCurrentLanguage())}"; - if (this.IsLocalisableLookup.TryGetValue(localeKey, out bool localisable)) + string localisedKey = $"{normalisedAssetName}.{this.GetLocale(this.GetCurrentLanguage())}"; + if (this.IsLocalisableLookup.TryGetValue(localisedKey, out bool localisable)) { return localisable - ? this.Cache.ContainsKey(localeKey) + ? this.Cache.ContainsKey(localisedKey) : this.Cache.ContainsKey(normalisedAssetName); } diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs index 66ef9181..4c362b0a 100644 --- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using Microsoft.Xna.Framework.Content; using StardewModdingAPI.Framework.Exceptions; @@ -45,7 +44,8 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The type of asset to inject. /// The asset path relative to the loader root directory, not including the .xnb extension. /// The asset value. - void Inject(string assetName, T value); + /// The language code for which to inject the asset. + void Inject(string assetName, T value, LocalizedContentManager.LanguageCode language); /// Get a copy of the given asset if supported. /// The asset type. @@ -63,7 +63,6 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Assert that the given key has a valid format and return a normalised form consistent with the underlying cache. /// The asset key to check. /// The asset key is empty or contains invalid characters. - [SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")] string AssertAndNormaliseAssetName(string assetName); /// Get the current content locale. diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index 2c50ec04..1df7d107 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -57,7 +57,7 @@ namespace StardewModdingAPI.Framework.ContentManagers if (contentManagerID != this.Name) { T data = this.Coordinator.LoadAndCloneManagedAsset(assetName, contentManagerID, relativePath, language); - this.Inject(assetName, data); + this.Inject(assetName, data, language); return data; } @@ -127,7 +127,7 @@ namespace StardewModdingAPI.Framework.ContentManagers { Texture2D texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, stream); texture = this.PremultiplyTransparency(texture); - this.Inject(internalKey, texture); + this.Inject(internalKey, texture, language); return (T)(object)texture; } diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index 8b86fdeb..e02748d2 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -126,7 +126,7 @@ namespace StardewModdingAPI.Framework.ModHelpers this.FixCustomTilesheetPaths(map, relativeMapPath: key); // inject map - this.ModContentManager.Inject(internalKey, map); + this.ModContentManager.Inject(internalKey, map, this.CurrentLocaleConstant); return (T)(object)map; } -- cgit From 78f28357e4f87ed619144229ea65c1e1cb0f9dd3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 15 Apr 2019 22:36:50 -0400 Subject: update code for SDV 1.4 (#638) --- docs/release-notes.md | 1 + .../Framework/Commands/Player/SetMoneyCommand.cs | 4 +- .../Framework/ItemData/ItemType.cs | 17 +-- .../Framework/ItemRepository.cs | 4 + src/SMAPI/Framework/SGame.cs | 120 ++++++++------------- src/SMAPI/Metadata/CoreAssetPropagator.cs | 4 +- 6 files changed, 64 insertions(+), 86 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 84738ff7..32f4db37 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,6 +3,7 @@ These changes have not been released yet. * For players: + * Updated for Stardew Valley 1.4. * Improved performance. * Updated mod compatibility list. * Fixed Save Backup not pruning old backups if they're uncompressed. diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs index ad11cc66..1706bbc1 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using StardewValley; namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player @@ -65,7 +65,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player public override void Update(IMonitor monitor) { if (this.InfiniteMoney) - Game1.player.money = 999999; + Game1.player.Money = 999999; } } } diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/ItemData/ItemType.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/ItemData/ItemType.cs index 7ee662d0..5d269c89 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/ItemData/ItemType.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/ItemData/ItemType.cs @@ -6,28 +6,31 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.ItemData /// A big craftable object in BigCraftable, - /// A item. + /// A item. Boots, - /// A flooring item. + /// A item. + Clothing, + + /// A flooring item. Flooring, - /// A item. + /// A item. Furniture, - /// A item. + /// A item. Hat, /// Any object in (except rings). Object, - /// A item. + /// A item. Ring, - /// A tool. + /// A tool. Tool, - /// A wall item. + /// A wall item. Wallpaper, /// A or item. diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs index fc631826..90cdb872 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/ItemRepository.cs @@ -35,6 +35,10 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework yield return new SearchableItem(ItemType.Tool, this.CustomIDOffset + 2, new Pan()); yield return new SearchableItem(ItemType.Tool, this.CustomIDOffset + 3, new Wand()); + // clothing + foreach (int id in Game1.clothingInformation.Keys) + yield return new SearchableItem(ItemType.Clothing, id, new Clothing(id)); + // wallpapers for (int id = 0; id < 112; id++) yield return new SearchableItem(ItemType.Wallpaper, id, new Wallpaper(id) { Category = SObject.furnitureCategory }); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 684ff3ba..c06f62cf 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -22,6 +22,7 @@ using StardewModdingAPI.Toolkit.Serialisation; using StardewValley; using StardewValley.BellsAndWhistles; using StardewValley.Buildings; +using StardewValley.Events; using StardewValley.Locations; using StardewValley.Menus; using StardewValley.TerrainFeatures; @@ -864,14 +865,14 @@ namespace StardewModdingAPI.Framework var events = this.Events; if (Game1._newDayTask != null) - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); else { if ((double)Game1.options.zoomLevel != 1.0) this.GraphicsDevice.SetRenderTarget(this.screen); if (this.IsSaving) { - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); IClickableMenu activeClickableMenu = Game1.activeClickableMenu; if (activeClickableMenu != null) { @@ -901,7 +902,7 @@ namespace StardewModdingAPI.Framework } else { - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); if (Game1.activeClickableMenu != null && Game1.options.showMenuBackground && Game1.activeClickableMenu.showWithoutTransparencyIfOptionIsSet()) { Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); @@ -925,7 +926,7 @@ namespace StardewModdingAPI.Framework if ((double)Game1.options.zoomLevel != 1.0) { this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); @@ -959,7 +960,7 @@ namespace StardewModdingAPI.Framework if ((double)Game1.options.zoomLevel == 1.0) return; this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); @@ -988,7 +989,7 @@ namespace StardewModdingAPI.Framework if ((double)Game1.options.zoomLevel == 1.0) return; this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); @@ -1003,7 +1004,7 @@ namespace StardewModdingAPI.Framework string str2 = Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3688"); string s = str2 + str1; string str3 = str2 + "... "; - int widthOfString = SpriteText.getWidthOfString(str3); + int widthOfString = SpriteText.getWidthOfString(str3, 999999); int height = 64; int x = 64; int y = Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - height; @@ -1014,7 +1015,7 @@ namespace StardewModdingAPI.Framework if ((double)Game1.options.zoomLevel != 1.0) { this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); @@ -1031,7 +1032,6 @@ namespace StardewModdingAPI.Framework { byte batchOpens = 0; // used for rendering event - Microsoft.Xna.Framework.Rectangle rectangle; Viewport viewport; if (Game1.gameMode == (byte)0) { @@ -1052,14 +1052,27 @@ namespace StardewModdingAPI.Framework for (int index = 0; index < Game1.currentLightSources.Count; ++index) { if (Utility.isOnScreen((Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position), (int)((double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) * 64.0 * 4.0))) - Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); + { + SpriteBatch spriteBatch = Game1.spriteBatch; + Texture2D lightTexture = Game1.currentLightSources.ElementAt(index).lightTexture; + Vector2 position = Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2); + Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds); + Color color = (Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color); + Microsoft.Xna.Framework.Rectangle bounds = Game1.currentLightSources.ElementAt(index).lightTexture.Bounds; + double x = (double)bounds.Center.X; + bounds = Game1.currentLightSources.ElementAt(index).lightTexture.Bounds; + double y = (double)bounds.Center.Y; + Vector2 origin = new Vector2((float)x, (float)y); + double num = (double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (double)(Game1.options.lightingQuality / 2); + spriteBatch.Draw(lightTexture, position, sourceRectangle, color, 0.0f, origin, (float)num, SpriteEffects.None, 0.9f); + } } Game1.spriteBatch.End(); this.GraphicsDevice.SetRenderTarget((double)Game1.options.zoomLevel == 1.0 ? (RenderTarget2D)null : this.screen); } if (Game1.bloomDay && Game1.bloom != null) Game1.bloom.BeginDraw(); - this.GraphicsDevice.Clear(this.bgColor); + this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); if (++batchOpens == 1) events.Rendering.RaiseEmpty(); @@ -1113,16 +1126,13 @@ namespace StardewModdingAPI.Framework Vector2 local = Game1.GlobalToLocal(farmerShadow.Position + new Vector2(32f, 24f)); Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); Color white = Color.White; - double num1 = 0.0; Microsoft.Xna.Framework.Rectangle bounds = Game1.shadowTexture.Bounds; double x = (double)bounds.Center.X; bounds = Game1.shadowTexture.Bounds; double y = (double)bounds.Center.Y; Vector2 origin = new Vector2((float)x, (float)y); - double num2 = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); - int num3 = 0; - double num4 = 0.0; - spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, (float)num1, origin, (float)num2, (SpriteEffects)num3, (float)num4); + double num = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); + spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, 0.0f, origin, (float)num, SpriteEffects.None, 0.0f); } } } @@ -1136,7 +1146,7 @@ namespace StardewModdingAPI.Framework { foreach (NPC character in Game1.currentLocation.characters) { - if (!(bool)((NetFieldBase)character.swimming) && !character.HideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(character.getTileLocation())) + if (!(bool)((NetFieldBase)character.swimming) && !character.HideShadow && (!(bool)((NetFieldBase)character.isInvisible) && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(character.getTileLocation()))) Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, character.Position + new Vector2((float)(character.Sprite.SpriteWidth * 4) / 2f, (float)(character.GetBoundingBox().Height + (character.IsMonster ? 0 : 12)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)character.yJumpOffset / 40.0) * (float)((NetFieldBase)character.scale), SpriteEffects.None, Math.Max(0.0f, (float)character.getStandingY() / 10000f) - 1E-06f); } } @@ -1157,16 +1167,13 @@ namespace StardewModdingAPI.Framework Vector2 local = Game1.GlobalToLocal(farmerShadow.Position + new Vector2(32f, 24f)); Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); Color white = Color.White; - double num1 = 0.0; Microsoft.Xna.Framework.Rectangle bounds = Game1.shadowTexture.Bounds; double x = (double)bounds.Center.X; bounds = Game1.shadowTexture.Bounds; double y = (double)bounds.Center.Y; Vector2 origin = new Vector2((float)x, (float)y); - double num2 = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); - int num3 = 0; - double num4 = 0.0; - spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, (float)num1, origin, (float)num2, (SpriteEffects)num3, (float)num4); + double num = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); + spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, 0.0f, origin, (float)num, SpriteEffects.None, 0.0f); } } } @@ -1199,29 +1206,8 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); if (Game1.displayFarmer && Game1.player.ActiveObject != null && ((bool)((NetFieldBase)Game1.player.ActiveObject.bigCraftable) && this.checkBigCraftableBoundariesForFrontLayer()) && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null) Game1.drawPlayerHeldObject(Game1.player); - else if (Game1.displayFarmer && Game1.player.ActiveObject != null) - { - if (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.Position.X, (int)Game1.player.Position.Y - 38), Game1.viewport.Size) == null || Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.Position.X, (int)Game1.player.Position.Y - 38), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways")) - { - Layer layer1 = Game1.currentLocation.Map.GetLayer("Front"); - rectangle = Game1.player.GetBoundingBox(); - Location mapDisplayLocation1 = new Location(rectangle.Right, (int)Game1.player.Position.Y - 38); - Size size1 = Game1.viewport.Size; - if (layer1.PickTile(mapDisplayLocation1, size1) != null) - { - Layer layer2 = Game1.currentLocation.Map.GetLayer("Front"); - rectangle = Game1.player.GetBoundingBox(); - Location mapDisplayLocation2 = new Location(rectangle.Right, (int)Game1.player.Position.Y - 38); - Size size2 = Game1.viewport.Size; - if (layer2.PickTile(mapDisplayLocation2, size2).TileIndexProperties.ContainsKey("FrontAlways")) - goto label_129; - } - else - goto label_129; - } + else if (Game1.displayFarmer && Game1.player.ActiveObject != null && (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.Position.X, (int)Game1.player.Position.Y - 38), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location((int)Game1.player.Position.X, (int)Game1.player.Position.Y - 38), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways") || Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.Position.Y - 38), Game1.viewport.Size) != null && !Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.GetBoundingBox().Right, (int)Game1.player.Position.Y - 38), Game1.viewport.Size).TileIndexProperties.ContainsKey("FrontAlways"))) Game1.drawPlayerHeldObject(Game1.player); - } - label_129: if ((Game1.player.UsingTool || Game1.pickingTool) && Game1.player.CurrentTool != null && ((!Game1.player.CurrentTool.Name.Equals("Seeds") || Game1.pickingTool) && (Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), (int)Game1.player.Position.Y - 38), Game1.viewport.Size) != null && Game1.currentLocation.Map.GetLayer("Front").PickTile(new Location(Game1.player.getStandingX(), Game1.player.getStandingY()), Game1.viewport.Size) == null))) Game1.drawTool(Game1.player); if (Game1.currentLocation.Map.GetLayer("AlwaysFront") != null) @@ -1329,17 +1315,16 @@ namespace StardewModdingAPI.Framework { int num4 = num3; viewport = Game1.graphics.GraphicsDevice.Viewport; - int width1 = viewport.Width; - if (num4 < width1) + int width = viewport.Width; + if (num4 < width) { SpriteBatch spriteBatch = Game1.spriteBatch; Texture2D staminaRect = Game1.staminaRect; int x = num3; int y = (int)num2; - int width2 = 1; viewport = Game1.graphics.GraphicsDevice.Viewport; int height = viewport.Height; - Microsoft.Xna.Framework.Rectangle destinationRectangle = new Microsoft.Xna.Framework.Rectangle(x, y, width2, height); + Microsoft.Xna.Framework.Rectangle destinationRectangle = new Microsoft.Xna.Framework.Rectangle(x, y, 1, height); Color color = Color.Red * 0.5f; spriteBatch.Draw(staminaRect, destinationRectangle, color); num3 += 64; @@ -1352,8 +1337,8 @@ namespace StardewModdingAPI.Framework { double num4 = (double)num5; viewport = Game1.graphics.GraphicsDevice.Viewport; - double height1 = (double)viewport.Height; - if (num4 < height1) + double height = (double)viewport.Height; + if (num4 < height) { SpriteBatch spriteBatch = Game1.spriteBatch; Texture2D staminaRect = Game1.staminaRect; @@ -1361,8 +1346,7 @@ namespace StardewModdingAPI.Framework int y = (int)num5; viewport = Game1.graphics.GraphicsDevice.Viewport; int width = viewport.Width; - int height2 = 1; - Microsoft.Xna.Framework.Rectangle destinationRectangle = new Microsoft.Xna.Framework.Rectangle(x, y, width, height2); + Microsoft.Xna.Framework.Rectangle destinationRectangle = new Microsoft.Xna.Framework.Rectangle(x, y, width, 1); Color color = Color.Red * 0.5f; spriteBatch.Draw(staminaRect, destinationRectangle, color); num5 += 64f; @@ -1379,9 +1363,11 @@ namespace StardewModdingAPI.Framework this.drawHUD(); events.RenderedHud.RaiseEmpty(); } - else if (Game1.activeClickableMenu == null && Game1.farmEvent == null) - Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2((float)Game1.getOldMouseX(), (float)Game1.getOldMouseY()), new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16)), Color.White, 0.0f, Vector2.Zero, (float)(4.0 + (double)Game1.dialogueButtonScale / 150.0), SpriteEffects.None, 1f); - if (Game1.hudMessages.Count > 0 && (!Game1.eventUp || Game1.isFestival())) + else if (Game1.activeClickableMenu == null) + { + FarmEvent farmEvent = Game1.farmEvent; + } + if (Game1.hudMessages.Count > 0) { for (int i = Game1.hudMessages.Count - 1; i >= 0; --i) Game1.hudMessages[i].draw(Game1.spriteBatch, i); @@ -1393,26 +1379,8 @@ namespace StardewModdingAPI.Framework this.drawDialogueBox(); if (Game1.progressBar) { - SpriteBatch spriteBatch1 = Game1.spriteBatch; - Texture2D fadeToBlackRect = Game1.fadeToBlackRect; - int x1 = (Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2; - rectangle = Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea(); - int y1 = rectangle.Bottom - 128; - int dialogueWidth = Game1.dialogueWidth; - int height1 = 32; - Microsoft.Xna.Framework.Rectangle destinationRectangle1 = new Microsoft.Xna.Framework.Rectangle(x1, y1, dialogueWidth, height1); - Color lightGray = Color.LightGray; - spriteBatch1.Draw(fadeToBlackRect, destinationRectangle1, lightGray); - SpriteBatch spriteBatch2 = Game1.spriteBatch; - Texture2D staminaRect = Game1.staminaRect; - int x2 = (Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2; - rectangle = Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea(); - int y2 = rectangle.Bottom - 128; - int width = (int)((double)Game1.pauseAccumulator / (double)Game1.pauseTime * (double)Game1.dialogueWidth); - int height2 = 32; - Microsoft.Xna.Framework.Rectangle destinationRectangle2 = new Microsoft.Xna.Framework.Rectangle(x2, y2, width, height2); - Color dimGray = Color.DimGray; - spriteBatch2.Draw(staminaRect, destinationRectangle2, dimGray); + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, Game1.dialogueWidth, 32), Color.LightGray); + Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, (int)((double)Game1.pauseAccumulator / (double)Game1.pauseTime * (double)Game1.dialogueWidth), 32), Color.DimGray); } if (Game1.eventUp && Game1.currentLocation != null && Game1.currentLocation.currentEvent != null) Game1.currentLocation.currentEvent.drawAfterMap(Game1.spriteBatch); @@ -1497,6 +1465,8 @@ namespace StardewModdingAPI.Framework } else if (Game1.farmEvent != null) Game1.farmEvent.drawAboveEverything(Game1.spriteBatch); + if (Game1.emoteMenu != null) + Game1.emoteMenu.draw(Game1.spriteBatch); if (Game1.HostPaused) { string s = Game1.content.LoadString("Strings\\StringsFromCSFiles:DayTimeMoneyBox.cs.10378"); diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index a64dc89b..c4086712 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -152,12 +152,12 @@ namespace StardewModdingAPI.Metadata case "characters\\farmer\\farmer_base": // Farmer if (Game1.player == null || !Game1.player.IsMale) return false; - return Game1.player.FarmerRenderer = new FarmerRenderer(key); + return Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); case "characters\\farmer\\farmer_girl_base": // Farmer if (Game1.player == null || Game1.player.IsMale) return false; - return Game1.player.FarmerRenderer = new FarmerRenderer(key); + return Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); case "characters\\farmer\\hairstyles": // Game1.loadContent return FarmerRenderer.hairStylesTexture = content.Load(key); -- cgit From abffdc2dab2a1c03904427b251acac9d800e0912 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 24 Apr 2019 23:45:34 -0400 Subject: simplify project names --- build/common.targets | 20 +-- build/prepare-install-package.targets | 12 +- src/SMAPI.Installer/SMAPI.Installer.csproj | 45 ++++++ .../StardewModdingAPI.Installer.csproj | 45 ------ src/SMAPI.Internal/SMAPI.Internal.shproj | 13 ++ .../StardewModdingAPI.Internal.shproj | 13 -- .../SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 2 +- .../SMAPI.ModBuildConfig.Analyzer.csproj | 24 +++ ...tardewModdingAPI.ModBuildConfig.Analyzer.csproj | 24 --- .../SMAPI.ModBuildConfig.csproj | 40 +++++ .../StardewModdingAPI.ModBuildConfig.csproj | 40 ----- .../SMAPI.Mods.ConsoleCommands.csproj | 35 +++++ .../StardewModdingAPI.Mods.ConsoleCommands.csproj | 35 ----- .../SMAPI.Mods.SaveBackup.csproj | 35 +++++ .../StardewModdingAPI.Mods.SaveBackup.csproj | 35 ----- src/SMAPI.Tests/SMAPI.Tests.csproj | 40 +++++ src/SMAPI.Tests/StardewModdingAPI.Tests.csproj | 40 ----- .../SMAPI.Toolkit.CoreInterfaces.csproj | 18 +++ ...StardewModdingAPI.Toolkit.CoreInterfaces.csproj | 18 --- src/SMAPI.Toolkit/SMAPI.Toolkit.csproj | 28 ++++ src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj | 28 ---- src/SMAPI.Web/SMAPI.Web.csproj | 46 ++++++ src/SMAPI.Web/StardewModdingAPI.Web.csproj | 46 ------ src/SMAPI.sln | 171 +++++++++++---------- src/SMAPI/SMAPI.csproj | 60 ++++++++ src/SMAPI/StardewModdingAPI.csproj | 60 -------- 26 files changed, 487 insertions(+), 486 deletions(-) create mode 100644 src/SMAPI.Installer/SMAPI.Installer.csproj delete mode 100644 src/SMAPI.Installer/StardewModdingAPI.Installer.csproj create mode 100644 src/SMAPI.Internal/SMAPI.Internal.shproj delete mode 100644 src/SMAPI.Internal/StardewModdingAPI.Internal.shproj create mode 100644 src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj delete mode 100644 src/SMAPI.ModBuildConfig.Analyzer/StardewModdingAPI.ModBuildConfig.Analyzer.csproj create mode 100644 src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj delete mode 100644 src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj create mode 100644 src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj delete mode 100644 src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj create mode 100644 src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj delete mode 100644 src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj create mode 100644 src/SMAPI.Tests/SMAPI.Tests.csproj delete mode 100644 src/SMAPI.Tests/StardewModdingAPI.Tests.csproj create mode 100644 src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj delete mode 100644 src/SMAPI.Toolkit.CoreInterfaces/StardewModdingAPI.Toolkit.CoreInterfaces.csproj create mode 100644 src/SMAPI.Toolkit/SMAPI.Toolkit.csproj delete mode 100644 src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj create mode 100644 src/SMAPI.Web/SMAPI.Web.csproj delete mode 100644 src/SMAPI.Web/StardewModdingAPI.Web.csproj create mode 100644 src/SMAPI/SMAPI.csproj delete mode 100644 src/SMAPI/StardewModdingAPI.csproj (limited to 'src/SMAPI') diff --git a/build/common.targets b/build/common.targets index 4aac55fc..9922bf15 100644 --- a/build/common.targets +++ b/build/common.targets @@ -32,12 +32,12 @@ - + - + @@ -47,15 +47,15 @@ $(GamePath)\Stardew Valley.exe - False + False $(GamePath)\StardewValley.GameData.dll - False + False $(GamePath)\Netcode.dll - False + False False @@ -79,7 +79,7 @@ $(GamePath)\StardewValley.GameData.MonoGame.dll - False + False $(GamePath)\MonoGame.Framework.dll @@ -114,7 +114,7 @@ - + @@ -124,17 +124,17 @@ - + - + - + diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index b7b70ed0..928191a2 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -40,12 +40,12 @@ - - - - - - + + + + + + diff --git a/src/SMAPI.Installer/SMAPI.Installer.csproj b/src/SMAPI.Installer/SMAPI.Installer.csproj new file mode 100644 index 00000000..a2e115e6 --- /dev/null +++ b/src/SMAPI.Installer/SMAPI.Installer.csproj @@ -0,0 +1,45 @@ + + + + SMAPI.Installer + SMAPI.Installer + net45 + false + latest + Exe + x86 + $(SolutionDir)\..\bin\$(Configuration)\Installer + false + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + diff --git a/src/SMAPI.Installer/StardewModdingAPI.Installer.csproj b/src/SMAPI.Installer/StardewModdingAPI.Installer.csproj deleted file mode 100644 index ac64a774..00000000 --- a/src/SMAPI.Installer/StardewModdingAPI.Installer.csproj +++ /dev/null @@ -1,45 +0,0 @@ - - - - StardewModdingAPI.Installer - StardewModdingAPI.Installer - net45 - false - latest - Exe - x86 - $(SolutionDir)\..\bin\$(Configuration)\Installer - false - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - diff --git a/src/SMAPI.Internal/SMAPI.Internal.shproj b/src/SMAPI.Internal/SMAPI.Internal.shproj new file mode 100644 index 00000000..a098828a --- /dev/null +++ b/src/SMAPI.Internal/SMAPI.Internal.shproj @@ -0,0 +1,13 @@ + + + + 85208f8d-6fd1-4531-be05-7142490f59fe + 14.0 + + + + + + + + diff --git a/src/SMAPI.Internal/StardewModdingAPI.Internal.shproj b/src/SMAPI.Internal/StardewModdingAPI.Internal.shproj deleted file mode 100644 index a098828a..00000000 --- a/src/SMAPI.Internal/StardewModdingAPI.Internal.shproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - 85208f8d-6fd1-4531-be05-7142490f59fe - 14.0 - - - - - - - - diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index 747a1d69..44e7ffab 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj new file mode 100644 index 00000000..1d8d7227 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj @@ -0,0 +1,24 @@ + + + + netstandard1.3 + false + false + bin + latest + + + + + + + + + + + + + + + + diff --git a/src/SMAPI.ModBuildConfig.Analyzer/StardewModdingAPI.ModBuildConfig.Analyzer.csproj b/src/SMAPI.ModBuildConfig.Analyzer/StardewModdingAPI.ModBuildConfig.Analyzer.csproj deleted file mode 100644 index 1d8d7227..00000000 --- a/src/SMAPI.ModBuildConfig.Analyzer/StardewModdingAPI.ModBuildConfig.Analyzer.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - netstandard1.3 - false - false - bin - latest - - - - - - - - - - - - - - - - diff --git a/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj new file mode 100644 index 00000000..f39a1555 --- /dev/null +++ b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj @@ -0,0 +1,40 @@ + + + + SMAPI.ModBuildConfig + SMAPI.ModBuildConfig + net45 + false + latest + x86 + false + + + + + + + + + mod-build-config.md + + + + + + + + + + + + + + mod-build-config.md + + + + + + + diff --git a/src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj b/src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj deleted file mode 100644 index 870973a0..00000000 --- a/src/SMAPI.ModBuildConfig/StardewModdingAPI.ModBuildConfig.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - - StardewModdingAPI.ModBuildConfig - StardewModdingAPI.ModBuildConfig - net45 - false - latest - x86 - false - - - - - - - - - mod-build-config.md - - - - - - - - - - - - - - mod-build-config.md - - - - - - - diff --git a/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj new file mode 100644 index 00000000..13f92443 --- /dev/null +++ b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj @@ -0,0 +1,35 @@ + + + + SMAPI.Mods.ConsoleCommands + ConsoleCommands + net45 + false + latest + $(SolutionDir)\..\bin\$(Configuration)\Mods\ConsoleCommands + false + x86 + + + + + False + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + PreserveNewest + + + + + + + diff --git a/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj b/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj deleted file mode 100644 index b535e2fd..00000000 --- a/src/SMAPI.Mods.ConsoleCommands/StardewModdingAPI.Mods.ConsoleCommands.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - StardewModdingAPI.Mods.ConsoleCommands - ConsoleCommands - net45 - false - latest - $(SolutionDir)\..\bin\$(Configuration)\Mods\ConsoleCommands - false - x86 - - - - - False - - - - - - Properties\GlobalAssemblyInfo.cs - - - - - - PreserveNewest - - - - - - - diff --git a/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj new file mode 100644 index 00000000..9375cb64 --- /dev/null +++ b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj @@ -0,0 +1,35 @@ + + + + SMAPI.Mods.SaveBackup + SaveBackup + net45 + false + latest + $(SolutionDir)\..\bin\$(Configuration)\Mods\SaveBackup + false + x86 + + + + + False + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + PreserveNewest + + + + + + + diff --git a/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj b/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj deleted file mode 100644 index 460f3c93..00000000 --- a/src/SMAPI.Mods.SaveBackup/StardewModdingAPI.Mods.SaveBackup.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - StardewModdingAPI.Mods.SaveBackup - SaveBackup - net45 - false - latest - $(SolutionDir)\..\bin\$(Configuration)\Mods\SaveBackup - false - x86 - - - - - False - - - - - - Properties\GlobalAssemblyInfo.cs - - - - - - PreserveNewest - - - - - - - diff --git a/src/SMAPI.Tests/SMAPI.Tests.csproj b/src/SMAPI.Tests/SMAPI.Tests.csproj new file mode 100644 index 00000000..1c414127 --- /dev/null +++ b/src/SMAPI.Tests/SMAPI.Tests.csproj @@ -0,0 +1,40 @@ + + + + SMAPI.Tests + SMAPI.Tests + net45 + false + latest + x86 + + + + + + + + + + + + + + + + + + + + + Properties\GlobalAssemblyInfo.cs + + + + + + + + + + diff --git a/src/SMAPI.Tests/StardewModdingAPI.Tests.csproj b/src/SMAPI.Tests/StardewModdingAPI.Tests.csproj deleted file mode 100644 index 68cf7b34..00000000 --- a/src/SMAPI.Tests/StardewModdingAPI.Tests.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - - StardewModdingAPI.Tests - StardewModdingAPI.Tests - net45 - false - latest - x86 - - - - - - - - - - - - - - - - - - - - - Properties\GlobalAssemblyInfo.cs - - - - - - - - - - diff --git a/src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj b/src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj new file mode 100644 index 00000000..7d8fc998 --- /dev/null +++ b/src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj @@ -0,0 +1,18 @@ + + + + net4.5;netstandard2.0 + SMAPI + false + ..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces + ..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces\$(TargetFramework)\SMAPI.Toolkit.CoreInterfaces.xml + latest + + + + + + + + + diff --git a/src/SMAPI.Toolkit.CoreInterfaces/StardewModdingAPI.Toolkit.CoreInterfaces.csproj b/src/SMAPI.Toolkit.CoreInterfaces/StardewModdingAPI.Toolkit.CoreInterfaces.csproj deleted file mode 100644 index cbbb7fc9..00000000 --- a/src/SMAPI.Toolkit.CoreInterfaces/StardewModdingAPI.Toolkit.CoreInterfaces.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net4.5;netstandard2.0 - StardewModdingAPI - false - ..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces - ..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces\$(TargetFramework)\StardewModdingAPI.Toolkit.CoreInterfaces.xml - latest - - - - - - - - - diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj new file mode 100644 index 00000000..8a029e62 --- /dev/null +++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj @@ -0,0 +1,28 @@ + + + + net4.5;netstandard2.0 + false + ..\..\bin\$(Configuration)\SMAPI.Toolkit + ..\..\bin\$(Configuration)\SMAPI.Toolkit\$(TargetFramework)\SMAPI.Toolkit.xml + latest + x86 + + + + + + + + + + + + + + + + + + + diff --git a/src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj b/src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj deleted file mode 100644 index a386fc5e..00000000 --- a/src/SMAPI.Toolkit/StardewModdingAPI.Toolkit.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net4.5;netstandard2.0 - false - ..\..\bin\$(Configuration)\SMAPI.Toolkit - ..\..\bin\$(Configuration)\SMAPI.Toolkit\$(TargetFramework)\StardewModdingAPI.Toolkit.xml - latest - x86 - - - - - - - - - - - - - - - - - - - diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj new file mode 100644 index 00000000..023a9333 --- /dev/null +++ b/src/SMAPI.Web/SMAPI.Web.csproj @@ -0,0 +1,46 @@ + + + + netcoreapp2.0 + false + latest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(IncludeRazorContentInPack) + + + $(IncludeRazorContentInPack) + + + PreserveNewest + + + + diff --git a/src/SMAPI.Web/StardewModdingAPI.Web.csproj b/src/SMAPI.Web/StardewModdingAPI.Web.csproj deleted file mode 100644 index 88a13f7b..00000000 --- a/src/SMAPI.Web/StardewModdingAPI.Web.csproj +++ /dev/null @@ -1,46 +0,0 @@ - - - - netcoreapp2.0 - false - latest - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(IncludeRazorContentInPack) - - - $(IncludeRazorContentInPack) - - - PreserveNewest - - - - diff --git a/src/SMAPI.sln b/src/SMAPI.sln index ffd50455..0a2d1511 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28729.10 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI", "SMAPI\StardewModdingAPI.csproj", "{1298F2B2-57BD-4647-AF70-1FCBBEE500B6}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".root", ".root", "{86C452BE-D2D8-45B4-B63F-E329EB06CEDA}" ProjectSection(SolutionItems) = preProject ..\.editorconfig = ..\.editorconfig @@ -13,25 +11,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".root", ".root", "{86C452BE ..\LICENSE.txt = ..\LICENSE.txt EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Installer", "SMAPI.Installer\StardewModdingAPI.Installer.csproj", "{0ED5EAD8-5D85-420D-8101-6D8CCCE29C9B}" - ProjectSection(ProjectDependencies) = postProject - {E4113F3E-3CAA-4288-9378-39A77BA625DB} = {E4113F3E-3CAA-4288-9378-39A77BA625DB} - {8C2CA4AB-BA8A-446A-B59E-9D6502E145F7} = {8C2CA4AB-BA8A-446A-B59E-9D6502E145F7} - {1298F2B2-57BD-4647-AF70-1FCBBEE500B6} = {1298F2B2-57BD-4647-AF70-1FCBBEE500B6} +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{4B1CEB70-F756-4A57-AAE8-8CD78C475F25}" + ProjectSection(SolutionItems) = preProject + ..\.github\CONTRIBUTING.md = ..\.github\CONTRIBUTING.md + ..\.github\SUPPORT.md = ..\.github\SUPPORT.md EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Tests", "SMAPI.Tests\StardewModdingAPI.Tests.csproj", "{E023DA12-5960-4101-80B9-A7DCE955725C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Web", "SMAPI.Web\StardewModdingAPI.Web.csproj", "{A308F679-51A3-4006-92D5-BAEC7EBD01A1}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Internal", "Internal", "{82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{EB35A917-67B9-4EFA-8DFC-4FB49B3949BB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{F4453AB6-D7D6-447F-A973-956CC777968F}" ProjectSection(SolutionItems) = preProject - ..\docs\mod-build-config.md = ..\docs\mod-build-config.md - ..\docs\README.md = ..\docs\README.md - ..\docs\release-notes.md = ..\docs\release-notes.md - ..\docs\technical-docs.md = ..\docs\technical-docs.md + ..\.github\ISSUE_TEMPLATE\bug_report.md = ..\.github\ISSUE_TEMPLATE\bug_report.md + ..\.github\ISSUE_TEMPLATE\feature_request.md = ..\.github\ISSUE_TEMPLATE\feature_request.md + ..\.github\ISSUE_TEMPLATE\general.md = ..\.github\ISSUE_TEMPLATE\general.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{09CF91E5-5BAB-4650-A200-E5EA9A633046}" @@ -42,34 +32,44 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{09CF91E5 ..\build\prepare-nuget-package.targets = ..\build\prepare-nuget-package.targets EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.ModBuildConfig", "SMAPI.ModBuildConfig\StardewModdingAPI.ModBuildConfig.csproj", "{C11D0AFB-2893-41A9-AD55-D002F032D6AD}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{EB35A917-67B9-4EFA-8DFC-4FB49B3949BB}" + ProjectSection(SolutionItems) = preProject + ..\docs\mod-build-config.md = ..\docs\mod-build-config.md + ..\docs\README.md = ..\docs\README.md + ..\docs\release-notes.md = ..\docs\release-notes.md + ..\docs\technical-docs.md = ..\docs\technical-docs.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Internal", "Internal", "{82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.ModBuildConfig.Analyzer", "SMAPI.ModBuildConfig.Analyzer\StardewModdingAPI.ModBuildConfig.Analyzer.csproj", "{80AD8528-AA49-4731-B4A6-C691845815A1}" +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SMAPI.Internal", "SMAPI.Internal\SMAPI.Internal.shproj", "{85208F8D-6FD1-4531-BE05-7142490F59FE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig.Analyzer.Tests", "SMAPI.ModBuildConfig.Analyzer.Tests\SMAPI.ModBuildConfig.Analyzer.Tests.csproj", "{0CF97929-B0D0-4D73-B7BF-4FF7191035F9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig.Analyzer.Tests", "SMAPI.ModBuildConfig.Analyzer.Tests\SMAPI.ModBuildConfig.Analyzer.Tests.csproj", "{680B2641-81EA-467C-86A5-0E81CDC57ED0}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "StardewModdingAPI.Internal", "SMAPI.Internal\StardewModdingAPI.Internal.shproj", "{85208F8D-6FD1-4531-BE05-7142490F59FE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests", "SMAPI.Tests\SMAPI.Tests.csproj", "{AA95884B-7097-476E-92C8-D0500DE9D6D1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Mods.ConsoleCommands", "SMAPI.Mods.ConsoleCommands\StardewModdingAPI.Mods.ConsoleCommands.csproj", "{8C2CA4AB-BA8A-446A-B59E-9D6502E145F7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI", "SMAPI\SMAPI.csproj", "{E6DA2198-7686-4F1D-B312-4A4DC70884C0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Mods.SaveBackup", "SMAPI.Mods.SaveBackup\StardewModdingAPI.Mods.SaveBackup.csproj", "{E4113F3E-3CAA-4288-9378-39A77BA625DB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Installer", "SMAPI.Installer\SMAPI.Installer.csproj", "{0A9BB24F-15FF-4C26-B1A2-81F7AE316518}" + ProjectSection(ProjectDependencies) = postProject + {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} + {CD53AD6F-97F4-4872-A212-50C2A0FD3601} = {CD53AD6F-97F4-4872-A212-50C2A0FD3601} + {E6DA2198-7686-4F1D-B312-4A4DC70884C0} = {E6DA2198-7686-4F1D-B312-4A4DC70884C0} + EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Toolkit", "SMAPI.Toolkit\StardewModdingAPI.Toolkit.csproj", "{EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig", "SMAPI.ModBuildConfig\SMAPI.ModBuildConfig.csproj", "{1B3821E6-D030-402C-B3A1-7CA45C2800EA}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Toolkit.CoreInterfaces", "SMAPI.Toolkit.CoreInterfaces\StardewModdingAPI.Toolkit.CoreInterfaces.csproj", "{D5CFD923-37F1-4BC3-9BE8-E506E202AC28}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig.Analyzer", "SMAPI.ModBuildConfig.Analyzer\SMAPI.ModBuildConfig.Analyzer.csproj", "{517677D7-7299-426F-B1A3-47BDCC2F1214}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{4B1CEB70-F756-4A57-AAE8-8CD78C475F25}" - ProjectSection(SolutionItems) = preProject - ..\.github\CONTRIBUTING.md = ..\.github\CONTRIBUTING.md - ..\.github\SUPPORT.md = ..\.github\SUPPORT.md - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Mods.ConsoleCommands", "SMAPI.Mods.ConsoleCommands\SMAPI.Mods.ConsoleCommands.csproj", "{0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{F4453AB6-D7D6-447F-A973-956CC777968F}" - ProjectSection(SolutionItems) = preProject - ..\.github\ISSUE_TEMPLATE\bug_report.md = ..\.github\ISSUE_TEMPLATE\bug_report.md - ..\.github\ISSUE_TEMPLATE\feature_request.md = ..\.github\ISSUE_TEMPLATE\feature_request.md - ..\.github\ISSUE_TEMPLATE\general.md = ..\.github\ISSUE_TEMPLATE\general.md - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Mods.SaveBackup", "SMAPI.Mods.SaveBackup\SMAPI.Mods.SaveBackup.csproj", "{CD53AD6F-97F4-4872-A212-50C2A0FD3601}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit", "SMAPI.Toolkit\SMAPI.Toolkit.csproj", "{08184F74-60AD-4EEE-A78C-F4A35ADE6246}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit.CoreInterfaces", "SMAPI.Toolkit.CoreInterfaces\SMAPI.Toolkit.CoreInterfaces.csproj", "{ED8E41FA-DDFA-4A77-932E-9853D279A129}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution @@ -80,61 +80,62 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1298F2B2-57BD-4647-AF70-1FCBBEE500B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1298F2B2-57BD-4647-AF70-1FCBBEE500B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1298F2B2-57BD-4647-AF70-1FCBBEE500B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1298F2B2-57BD-4647-AF70-1FCBBEE500B6}.Release|Any CPU.Build.0 = Release|Any CPU - {0ED5EAD8-5D85-420D-8101-6D8CCCE29C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0ED5EAD8-5D85-420D-8101-6D8CCCE29C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0ED5EAD8-5D85-420D-8101-6D8CCCE29C9B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0ED5EAD8-5D85-420D-8101-6D8CCCE29C9B}.Release|Any CPU.Build.0 = Release|Any CPU - {E023DA12-5960-4101-80B9-A7DCE955725C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E023DA12-5960-4101-80B9-A7DCE955725C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E023DA12-5960-4101-80B9-A7DCE955725C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E023DA12-5960-4101-80B9-A7DCE955725C}.Release|Any CPU.Build.0 = Release|Any CPU - {A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A308F679-51A3-4006-92D5-BAEC7EBD01A1}.Release|Any CPU.Build.0 = Release|Any CPU - {C11D0AFB-2893-41A9-AD55-D002F032D6AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C11D0AFB-2893-41A9-AD55-D002F032D6AD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C11D0AFB-2893-41A9-AD55-D002F032D6AD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C11D0AFB-2893-41A9-AD55-D002F032D6AD}.Release|Any CPU.Build.0 = Release|Any CPU - {80AD8528-AA49-4731-B4A6-C691845815A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {80AD8528-AA49-4731-B4A6-C691845815A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {80AD8528-AA49-4731-B4A6-C691845815A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {80AD8528-AA49-4731-B4A6-C691845815A1}.Release|Any CPU.Build.0 = Release|Any CPU - {0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0CF97929-B0D0-4D73-B7BF-4FF7191035F9}.Release|Any CPU.Build.0 = Release|Any CPU - {EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EA5CFD2E-9453-4D29-B80F-8E0EA23F4AC6}.Release|Any CPU.Build.0 = Release|Any CPU - {D5CFD923-37F1-4BC3-9BE8-E506E202AC28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D5CFD923-37F1-4BC3-9BE8-E506E202AC28}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D5CFD923-37F1-4BC3-9BE8-E506E202AC28}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D5CFD923-37F1-4BC3-9BE8-E506E202AC28}.Release|Any CPU.Build.0 = Release|Any CPU - {8C2CA4AB-BA8A-446A-B59E-9D6502E145F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C2CA4AB-BA8A-446A-B59E-9D6502E145F7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C2CA4AB-BA8A-446A-B59E-9D6502E145F7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C2CA4AB-BA8A-446A-B59E-9D6502E145F7}.Release|Any CPU.Build.0 = Release|Any CPU - {E4113F3E-3CAA-4288-9378-39A77BA625DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4113F3E-3CAA-4288-9378-39A77BA625DB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4113F3E-3CAA-4288-9378-39A77BA625DB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4113F3E-3CAA-4288-9378-39A77BA625DB}.Release|Any CPU.Build.0 = Release|Any CPU + {680B2641-81EA-467C-86A5-0E81CDC57ED0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {680B2641-81EA-467C-86A5-0E81CDC57ED0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {680B2641-81EA-467C-86A5-0E81CDC57ED0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {680B2641-81EA-467C-86A5-0E81CDC57ED0}.Release|Any CPU.Build.0 = Release|Any CPU + {AA95884B-7097-476E-92C8-D0500DE9D6D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA95884B-7097-476E-92C8-D0500DE9D6D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA95884B-7097-476E-92C8-D0500DE9D6D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA95884B-7097-476E-92C8-D0500DE9D6D1}.Release|Any CPU.Build.0 = Release|Any CPU + {E6DA2198-7686-4F1D-B312-4A4DC70884C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6DA2198-7686-4F1D-B312-4A4DC70884C0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6DA2198-7686-4F1D-B312-4A4DC70884C0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6DA2198-7686-4F1D-B312-4A4DC70884C0}.Release|Any CPU.Build.0 = Release|Any CPU + {0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A9BB24F-15FF-4C26-B1A2-81F7AE316518}.Release|Any CPU.Build.0 = Release|Any CPU + {1B3821E6-D030-402C-B3A1-7CA45C2800EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B3821E6-D030-402C-B3A1-7CA45C2800EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B3821E6-D030-402C-B3A1-7CA45C2800EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B3821E6-D030-402C-B3A1-7CA45C2800EA}.Release|Any CPU.Build.0 = Release|Any CPU + {517677D7-7299-426F-B1A3-47BDCC2F1214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {517677D7-7299-426F-B1A3-47BDCC2F1214}.Debug|Any CPU.Build.0 = Debug|Any CPU + {517677D7-7299-426F-B1A3-47BDCC2F1214}.Release|Any CPU.ActiveCfg = Release|Any CPU + {517677D7-7299-426F-B1A3-47BDCC2F1214}.Release|Any CPU.Build.0 = Release|Any CPU + {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F}.Release|Any CPU.Build.0 = Release|Any CPU + {CD53AD6F-97F4-4872-A212-50C2A0FD3601}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD53AD6F-97F4-4872-A212-50C2A0FD3601}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD53AD6F-97F4-4872-A212-50C2A0FD3601}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD53AD6F-97F4-4872-A212-50C2A0FD3601}.Release|Any CPU.Build.0 = Release|Any CPU + {08184F74-60AD-4EEE-A78C-F4A35ADE6246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08184F74-60AD-4EEE-A78C-F4A35ADE6246}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08184F74-60AD-4EEE-A78C-F4A35ADE6246}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08184F74-60AD-4EEE-A78C-F4A35ADE6246}.Release|Any CPU.Build.0 = Release|Any CPU + {ED8E41FA-DDFA-4A77-932E-9853D279A129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED8E41FA-DDFA-4A77-932E-9853D279A129}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED8E41FA-DDFA-4A77-932E-9853D279A129}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED8E41FA-DDFA-4A77-932E-9853D279A129}.Release|Any CPU.Build.0 = Release|Any CPU + {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {E023DA12-5960-4101-80B9-A7DCE955725C} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} - {EB35A917-67B9-4EFA-8DFC-4FB49B3949BB} = {86C452BE-D2D8-45B4-B63F-E329EB06CEDA} - {09CF91E5-5BAB-4650-A200-E5EA9A633046} = {86C452BE-D2D8-45B4-B63F-E329EB06CEDA} - {0CF97929-B0D0-4D73-B7BF-4FF7191035F9} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} {4B1CEB70-F756-4A57-AAE8-8CD78C475F25} = {86C452BE-D2D8-45B4-B63F-E329EB06CEDA} {F4453AB6-D7D6-447F-A973-956CC777968F} = {4B1CEB70-F756-4A57-AAE8-8CD78C475F25} + {09CF91E5-5BAB-4650-A200-E5EA9A633046} = {86C452BE-D2D8-45B4-B63F-E329EB06CEDA} + {EB35A917-67B9-4EFA-8DFC-4FB49B3949BB} = {86C452BE-D2D8-45B4-B63F-E329EB06CEDA} + {85208F8D-6FD1-4531-BE05-7142490F59FE} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} + {680B2641-81EA-467C-86A5-0E81CDC57ED0} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} + {AA95884B-7097-476E-92C8-D0500DE9D6D1} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC} diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj new file mode 100644 index 00000000..58a71f94 --- /dev/null +++ b/src/SMAPI/SMAPI.csproj @@ -0,0 +1,60 @@ + + + + StardewModdingAPI + StardewModdingAPI + net45 + false + latest + x86 + Exe + $(SolutionDir)\..\bin\$(Configuration)\SMAPI + $(SolutionDir)\..\bin\$(Configuration)\SMAPI\StardewModdingAPI.xml + false + true + icon.ico + + + + + + + + + + + + True + + + True + + + + + + + + + + + + + + + + PreserveNewest + + + StardewModdingAPI.metadata.json + PreserveNewest + + + PreserveNewest + + + + + + + diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj deleted file mode 100644 index 718366a7..00000000 --- a/src/SMAPI/StardewModdingAPI.csproj +++ /dev/null @@ -1,60 +0,0 @@ - - - - StardewModdingAPI - StardewModdingAPI - net45 - false - latest - x86 - Exe - $(SolutionDir)\..\bin\$(Configuration)\SMAPI - $(SolutionDir)\..\bin\$(Configuration)\SMAPI\StardewModdingAPI.xml - false - true - icon.ico - - - - - - - - - - - - True - - - True - - - - - - - - - - - - - - - - PreserveNewest - - - StardewModdingAPI.metadata.json - PreserveNewest - - - PreserveNewest - - - - - - - -- cgit From c15785a68d3e99959cdcca5bfb51e8686316a33b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 24 Apr 2019 23:46:52 -0400 Subject: simplify config.json and metadata.json names --- build/common.targets | 4 +- build/prepare-install-package.targets | 6 +- docs/technical-docs.md | 4 +- src/SMAPI.Installer/Framework/InstallerPaths.cs | 2 +- src/SMAPI.Installer/InteractiveInstaller.cs | 3 +- src/SMAPI.Installer/README.txt | 4 +- src/SMAPI.Web/Controllers/ModsApiController.cs | 2 +- src/SMAPI.Web/SMAPI.Web.csproj | 2 +- src/SMAPI.Web/Views/Index/Privacy.cshtml | 2 +- src/SMAPI.Web/wwwroot/SMAPI.metadata.json | 507 +++++++++++++++++++++ .../wwwroot/StardewModdingAPI.metadata.json | 507 --------------------- src/SMAPI/Constants.cs | 4 +- src/SMAPI/SMAPI.config.json | 77 ++++ src/SMAPI/SMAPI.csproj | 6 +- src/SMAPI/StardewModdingAPI.config.json | 77 ---- 15 files changed, 603 insertions(+), 604 deletions(-) create mode 100644 src/SMAPI.Web/wwwroot/SMAPI.metadata.json delete mode 100644 src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json create mode 100644 src/SMAPI/SMAPI.config.json delete mode 100644 src/SMAPI/StardewModdingAPI.config.json (limited to 'src/SMAPI') diff --git a/build/common.targets b/build/common.targets index 9922bf15..b42ef063 100644 --- a/build/common.targets +++ b/build/common.targets @@ -118,8 +118,8 @@ - - + + diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index 928191a2..18a69a24 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -38,8 +38,8 @@ - - + + @@ -76,7 +76,7 @@ - + diff --git a/docs/technical-docs.md b/docs/technical-docs.md index 545f4aa3..5598b7a8 100644 --- a/docs/technical-docs.md +++ b/docs/technical-docs.md @@ -70,8 +70,8 @@ on the wiki for the first-time setup. ## Customisation ### Configuration file -You can customise the SMAPI behaviour by editing the `smapi-internal/StardewModdingAPI.config.json` -file in your game folder. +You can customise the SMAPI behaviour by editing the `smapi-internal/config.json` file in your game +folder. Basic fields: diff --git a/src/SMAPI.Installer/Framework/InstallerPaths.cs b/src/SMAPI.Installer/Framework/InstallerPaths.cs index e5396018..9393e14f 100644 --- a/src/SMAPI.Installer/Framework/InstallerPaths.cs +++ b/src/SMAPI.Installer/Framework/InstallerPaths.cs @@ -59,7 +59,7 @@ namespace StardewModdingAPI.Installer.Framework this.UnixLauncherPath = Path.Combine(gameDir.FullName, "StardewValley"); this.UnixSmapiLauncherPath = Path.Combine(gameDir.FullName, "StardewModdingAPI"); this.UnixBackupLauncherPath = Path.Combine(gameDir.FullName, "StardewValley-original"); - this.ApiConfigPath = Path.Combine(gameDir.FullName, "smapi-internal", "StardewModdingAPI.config.json"); + this.ApiConfigPath = Path.Combine(gameDir.FullName, "smapi-internal", "config.json"); } } } diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 7148b1d9..c8d36b01 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -112,6 +112,7 @@ namespace StardewModdingApi.Installer yield return GetInstallPath("StardewModdingAPI.pdb"); // Windows only yield return GetInstallPath("StardewModdingAPI.xml"); yield return GetInstallPath("smapi-internal"); + yield return GetInstallPath("steam_appid.txt"); // obsolete yield return GetInstallPath(Path.Combine("Mods", ".cache")); // 1.3-1.4 @@ -133,11 +134,9 @@ namespace StardewModdingApi.Installer yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.dll"); // moved in 2.8 yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.pdb"); // moved in 2.8 yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.xml"); // moved in 2.8 - yield return GetInstallPath("StardewModdingAPI.xml"); // moved in 2.8 yield return GetInstallPath("System.Numerics.dll"); // moved in 2.8 yield return GetInstallPath("System.Runtime.Caching.dll"); // moved in 2.8 yield return GetInstallPath("System.ValueTuple.dll"); // moved in 2.8 - yield return GetInstallPath("steam_appid.txt"); // moved in 2.8 if (modsDir.Exists) { diff --git a/src/SMAPI.Installer/README.txt b/src/SMAPI.Installer/README.txt index 79c90cc0..0da49a46 100644 --- a/src/SMAPI.Installer/README.txt +++ b/src/SMAPI.Installer/README.txt @@ -40,5 +40,5 @@ When installing on Linux or Mac: - Make sure Mono is installed (normally the installer checks for you). While it's not required, many mods won't work correctly without it. (Specifically, mods which load PNG images may crash or freeze the game.) -- To configure the color scheme, edit the `smapi-internal/StardewModdingAPI.config.json` file and - see instructions there for the 'ColorScheme' setting. +- To configure the color scheme, edit the `smapi-internal/config.json` file and see instructions + there for the 'ColorScheme' setting. diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index 7e6f592c..9cffd3b3 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -65,7 +65,7 @@ namespace StardewModdingAPI.Web.Controllers /// The Nexus API client. public ModsApiController(IHostingEnvironment environment, IMemoryCache cache, IOptions configProvider, IChucklefishClient chucklefish, IGitHubClient github, IModDropClient modDrop, INexusClient nexus) { - this.ModDatabase = new ModToolkit().GetModDatabase(Path.Combine(environment.WebRootPath, "StardewModdingAPI.metadata.json")); + this.ModDatabase = new ModToolkit().GetModDatabase(Path.Combine(environment.WebRootPath, "SMAPI.metadata.json")); ModUpdateCheckConfig config = configProvider.Value; this.CompatibilityPageUrl = config.CompatibilityPageUrl; diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj index 023a9333..1d8e41c6 100644 --- a/src/SMAPI.Web/SMAPI.Web.csproj +++ b/src/SMAPI.Web/SMAPI.Web.csproj @@ -38,7 +38,7 @@ $(IncludeRazorContentInPack) - + PreserveNewest diff --git a/src/SMAPI.Web/Views/Index/Privacy.cshtml b/src/SMAPI.Web/Views/Index/Privacy.cshtml index ca99eef6..356580b4 100644 --- a/src/SMAPI.Web/Views/Index/Privacy.cshtml +++ b/src/SMAPI.Web/Views/Index/Privacy.cshtml @@ -29,7 +29,7 @@

You can disable update checks, and no information will be transmitted to the web API. To do so:

  1. find your game folder;
  2. -
  3. open the smapi-internal/StardewModdingAPI.config.json file in a text editor;
  4. +
  5. open the smapi-internal/config.json file in a text editor;
  6. change "CheckForUpdates": true to "CheckForUpdates": false.
diff --git a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json new file mode 100644 index 00000000..f1e0023e --- /dev/null +++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json @@ -0,0 +1,507 @@ +{ + /** + * Metadata about some SMAPI mods used in compatibility, update, and dependency checks. This + * field shouldn't be edited by players in most cases. + * + * Standard fields + * =============== + * The predefined fields are documented below (only 'ID' is required). Each entry's key is the + * default display name for the mod if one isn't available (e.g. in dependency checks). + * + * - ID: the mod's latest unique ID (if any). + * + * - FormerIDs: uniquely identifies the mod across multiple versions, and supports matching + * other fields if no ID was specified. This doesn't include the latest ID, if any. Multiple + * variants can be separated with '|'. + * + * - MapLocalVersions and MapRemoteVersions correct local manifest versions and remote versions + * during update checks. For example, if the API returns version '1.1-1078' where '1078' is + * intended to be a build number, MapRemoteVersions can map it to '1.1' when comparing to the + * mod's current version. This is only meant to support legacy mods with injected update keys. + * + * Versioned metadata + * ================== + * Each record can also specify extra metadata using the field keys below. + * + * Each key consists of a field name prefixed with any combination of version range and 'Default', + * separated by pipes (whitespace trimmed). For example, 'UpdateKey' will always override, + * 'Default | UpdateKey' will only override if the mod has no update keys, and + * '~1.1 | Default | Name' will do the same up to version 1.1. + * + * The version format is 'min~max' (where either side can be blank for unbounded), or a single + * version number. + * + * These are the valid field names: + * + * - UpdateKey: the update key to set in the mod's manifest. This is used to enable update + * checks for older mods that haven't been updated to use it yet. + * + * - Status: overrides compatibility checks. The possible values are Obsolete (SMAPI won't load + * it because the mod should no longer be used), AssumeBroken (SMAPI won't load it because + * the specified version isn't compatible), or AssumeCompatible (SMAPI will try to load it + * even if it detects incompatible code). + * + * Note that this shouldn't be set to 'AssumeBroken' if SMAPI can detect the incompatibility + * automatically, since that hides the details from trace logs. + * + * - StatusReasonPhrase: a message to show to the player explaining why the mod can't be loaded + * (if applicable). If blank, will default to a generic not-compatible message. + * + * - AlternativeUrl: a URL where the player can find an unofficial update or alternative if the + * mod is no longer compatible. + */ + "ModData": { + /********* + ** Common dependencies for friendly errors + *********/ + "Advanced Location Loader": { + "ID": "Entoarox.AdvancedLocationLoader", + "Default | UpdateKey": "Nexus:2270" + }, + + //"Content Patcher": { + // "ID": "Pathoschild.ContentPatcher", + // "Default | UpdateKey": "Nexus:1915" + //}, + + //"Custom Farming Redux": { + // "ID": "Platonymous.CustomFarming", + // "Default | UpdateKey": "Nexus:991" + //}, + + "Custom Shirts": { + "ID": "Platonymous.CustomShirts", + "Default | UpdateKey": "Nexus:2416" + }, + + "Entoarox Framework": { + "ID": "Entoarox.EntoaroxFramework", + "Default | UpdateKey": "Nexus:2269" + }, + + "JSON Assets": { + "ID": "spacechase0.JsonAssets", + "Default | UpdateKey": "Nexus:1720", + "1.3.1 | Status": "AssumeBroken" // causes runtime crashes + }, + + "Mail Framework": { + "ID": "DIGUS.MailFrameworkMod", + "Default | UpdateKey": "Nexus:1536" + }, + + "MTN": { + "ID": "SgtPickles.MTN", + "Default | UpdateKey": "Nexus:2256", + "~1.2.6 | Status": "AssumeBroken" // replaces Game1.multiplayer, which breaks SMAPI's multiplayer API. + }, + + "PyTK": { + "ID": "Platonymous.Toolkit", + "Default | UpdateKey": "Nexus:1726" + }, + + "Rubydew": { + "ID": "bwdy.rubydew", + "SuppressWarnings": "UsesDynamic", // mod explicitly loads DLLs for Linux/Mac compatibility + "Default | UpdateKey": "Nexus:3656" + }, + + "SpaceCore": { + "ID": "spacechase0.SpaceCore", + "Default | UpdateKey": "Nexus:1348" + }, + + "Stardust Core": { + "ID": "Omegasis.StardustCore", + "Default | UpdateKey": "Nexus:2341" + }, + + "TMX Loader": { + "ID": "Platonymous.TMXLoader", + "Default | UpdateKey": "Nexus:1820" + }, + + + /********* + ** Map versions + *********/ + "Adjust Artisan Prices": { + "ID": "ThatNorthernMonkey.AdjustArtisanPrices", + "FormerIDs": "1e36d4ca-c7ef-4dfb-9927-d27a6c3c8bdc", // changed in 0.0.2-pathoschild-update + "MapRemoteVersions": { "0.01": "0.0.1" } + }, + + "Almighty Farming Tool": { + "ID": "439", + "MapRemoteVersions": { + "1.21": "1.2.1", + "1.22-unofficial.3.mizzion": "1.2.2-unofficial.3.mizzion" + } + }, + + "Basic Sprinkler Improved": { + "ID": "lrsk_sdvm_bsi.0117171308", + "MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated + }, + + "Better Shipping Box": { + "ID": "Kithio:BetterShippingBox", + "MapLocalVersions": { "1.0.1": "1.0.2" } + }, + + "Chefs Closet": { + "ID": "Duder.ChefsCloset", + "MapLocalVersions": { "1.3-1": "1.3" } + }, + + "Configurable Machines": { + "ID": "21da6619-dc03-4660-9794-8e5b498f5b97", + "MapLocalVersions": { "1.2-beta": "1.2" } + }, + + "Crafting Counter": { + "ID": "lolpcgaming.CraftingCounter", + "MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest + }, + + "Custom Linens": { + "ID": "Mevima.CustomLinens", + "MapRemoteVersions": { "1.1": "1.0" } // manifest not updated + }, + + "Dynamic Horses": { + "ID": "Bpendragon-DynamicHorses", + "MapRemoteVersions": { "1.2": "1.1-release" } // manifest not updated + }, + + "Dynamic Machines": { + "ID": "DynamicMachines", + "MapLocalVersions": { "1.1": "1.1.1" } + }, + + "Multiple Sprites and Portraits On Rotation (File Loading)": { + "ID": "FileLoading", + "MapLocalVersions": { "1.1": "1.12" } + }, + + "Relationship Status": { + "ID": "relationshipstatus", + "MapRemoteVersions": { "1.0.5": "1.0.4" } // not updated in manifest + }, + + "ReRegeneration": { + "ID": "lrsk_sdvm_rerg.0925160827", + "MapLocalVersions": { "1.1.2-release": "1.1.2" } + }, + + "Showcase Mod": { + "ID": "Igorious.Showcase", + "MapLocalVersions": { "0.9-500": "0.9" } + }, + + "Siv's Marriage Mod": { + "ID": "6266959802", // official version + "FormerIDs": "Siv.MarriageMod | medoli900.Siv's Marriage Mod", // 1.2.3-unofficial versions + "MapLocalVersions": { "0.0": "1.4" } + }, + + + /********* + ** Obsolete + *********/ + "Animal Mood Fix": { + "ID": "GPeters-AnimalMoodFix", + "~ | Status": "Obsolete", + "~ | StatusReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2." + }, + + "Colored Chests": { + "ID": "4befde5c-731c-4853-8e4b-c5cdf946805f", + "~ | Status": "Obsolete", + "~ | StatusReasonPhrase": "colored chests were added in Stardew Valley 1.1." + }, + + "Modder Serialization Utility": { + "ID": "SerializerUtils-0-1", + "~ | Status": "Obsolete", + "~ | StatusReasonPhrase": "it's no longer maintained or used." + }, + + "No Debug Mode": { + "ID": "NoDebugMode", + "~ | Status": "Obsolete", + "~ | StatusReasonPhrase": "debug mode was removed in SMAPI 1.0." + }, + + /********* + ** Broke in SDV 1.4 + *********/ + "Loved Labels": { + "ID": "Advize.LovedLabels", + "~2.2.1-unofficial.2-pathoschild | Status": "AssumeBroken" // runtime reflection errors + }, + + /********* + ** Broke in SMAPI 3.0 (runtime errors due to lifecycle changes) + *********/ + "Advancing Sprinklers": { + "ID": "warix3.advancingsprinklers", + "~1.0.0 | Status": "AssumeBroken" + }, + + "Arcade 2048": { + "ID": "Platonymous.2048", + "~1.0.6 | Status": "AssumeBroken" // possibly due to PyTK + }, + + "Arcade Snake": { + "ID": "Platonymous.Snake", + "~1.1.0 | Status": "AssumeBroken" // possibly due to PyTK + }, + + "Better Sprinklers": { + "ID": "Speeder.BetterSprinklers", + "~2.3.1-unofficial.7-pathoschild | Status": "AssumeBroken" + }, + + "Content Patcher": { + "ID": "Pathoschild.ContentPatcher", + "Default | UpdateKey": "Nexus:1915", + "~1.6.4 | Status": "AssumeBroken" + }, + + "Custom Adventure Guild Challenges": { + "ID": "DefenTheNation.CustomGuildChallenges", + "~1.8 | Status": "AssumeBroken" + }, + + "Custom Farming Redux": { + "ID": "Platonymous.CustomFarming", + "Default | UpdateKey": "Nexus:991", + "~2.10.10 | Status": "AssumeBroken" // possibly due to PyTK + }, + + "JoJaBan - Arcade Sokoban": { + "ID": "Platonymous.JoJaBan", + "~0.4.3 | Status": "AssumeBroken" // possibly due to PyTK + }, + + "Level Extender": { + "ID": "DevinLematty.LevelExtender", + "~3.1 | Status": "AssumeBroken" + }, + + "Mod Update Menu": { + "ID": "cat.modupdatemenu", + "~1.4 | Status": "AssumeBroken" + }, + + "Quick Start": { + "ID": "WuestMan.QuickStart", + "~1.5 | Status": "AssumeBroken" + }, + + "Seed Bag": { + "ID": "Platonymous.SeedBag", + "~1.2.7 | Status": "AssumeBroken" // possibly due to PyTK + }, + + /********* + ** Broke in SDV 1.3.36 + *********/ + "2cute FarmCave": { + "ID": "taintedwheat.2CuteFarmCave", + "Default | UpdateKey": "Nexus:843", + "~2.0 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + "Ace's Expanded Caves - Default Cave": { + "ID": "Acerbicon.AECdefault", + "Default | UpdateKey": "Nexus:2131", + "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + "Ace's Expanded Caves - Desert Cave": { + "ID": "Acerbicon.AECdesert", + "Default | UpdateKey": "Nexus:2131", + "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + "Ace's Expanded Caves - Ice Cave": { + "ID": "Acerbicon.AECice", + "Default | UpdateKey": "Nexus:2131", + "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + "Ace's Expanded Caves - Lava Cave": { + "ID": "Acerbicon.AEClava", + "Default | UpdateKey": "Nexus:2131", + "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + "Ace's Expanded Caves - Slime Cave": { + "ID": "Acerbicon.AECslime", + "Default | UpdateKey": "Nexus:2131", + "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + "Green Pastures Farm": { + "ID": "bugbuddy.GreenPasturesFarm", + "Default | UpdateKey": "Nexus:2326", + "~1.0 | Status": "AssumeBroken" // references deleted Content/weapons.xnb + }, + + "Immersive Farm 2": { + "ID": "zander.immersivefarm2", + "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + "Karmylla's Immersive Map Edits": { + "ID": "Karmylla.ImmersiveMapEdits", + "Default | UpdateKey": "Nexus:1149", + "~2.4 | Status": "AssumeBroken" // references deleted Content/weapons.xnb + }, + + "Secret Gardens Greenhouse": { + "ID": "jessebot.secretgardens", + "Default | UpdateKey": "Nexus:3067", + "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb + }, + + /********* + ** Broke circa SDV 1.3 + *********/ + "Canon-Friendly Dialogue Expansion": { + "ID": "gizzymo.canonfriendlyexpansion", + "~1.1.1 | Status": "AssumeBroken" // causes a save crash on certain dates + }, + + "Everytime Submarine": { + "ID": "MustafaDemirel.EverytimeSubmarine", + "~1.0.0 | Status": "AssumeBroken" // breaks player saves if their beach bridge is fixed + }, + + "Always Scroll Map": { + "ID": "bcmpinc.AlwaysScrollMap", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "Arcade Pong": { + "ID": "Platonymous.ArcadePong", + "~1.0.2 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals + }, + + "BJS Night Sounds": { + "ID": "BunnyJumps.BJSNightSounds", + "~1.0.0 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ + }, + + "Craft Counter": { + "ID": "bcmpinc.CraftCounter", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "Fishing Adjust": { + "ID": "shuaiz.FishingAdjustMod", + "~2.0.1 | Status": "AssumeBroken" // Method not found: 'Void Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase, Harmony.HarmonyMethod, Harmony.HarmonyMethod, Harmony.HarmonyMethod)' + }, + + "Fishing Automaton": { + "ID": "Drynwynn.FishingAutomaton", + "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ + }, + + "Fix Animal Tools": { + "ID": "bcmpinc.FixAnimalTools", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "Fix Scythe Exp": { + "ID": "bcmpinc.FixScytheExp", + "~0.3 | Status": "AssumeBroken" // broke in 1.3: Exception from HarmonyInstance "bcmpinc.FixScytheExp" [...] Bad label content in ILGenerator. + }, + + "Grass Growth": { + "ID": "bcmpinc.GrassGrowth", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "More Silo Storage": { + "ID": "OrneryWalrus.MoreSiloStorage", + "~1.0.1 | Status": "AssumeBroken" // broke in SDV 1.3 + }, + + "Movement Speed": { + "ID": "bcmpinc.MovementSpeed", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "No Added Flying Mine Monsters": { + "ID": "Drynwynn.NoAddedFlyingMineMonsters", + "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ + }, + + "Server Bookmarker": { + "ID": "Ilyaki.ServerBookmarker", + "~1.0.0 | Status": "AssumeBroken" // broke in Stardew Valley 1.3.29 (runtime errors) + }, + + "Skill Prestige: Cooking Adapter": { + "ID": "Alphablackwolf.CookingSkillPrestigeAdapter", + "FormerIDs": "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63", // changed circa 1.1 + "MapRemoteVersions": { "1.2.3": "1.1" } // manifest not updated + }, + + "Skull Cave Saver": { + "ID": "cantorsdust.SkullCaveSaver", + "FormerIDs": "8ac06349-26f7-4394-806c-95d48fd35774 | community.SkullCaveSaver", // changed in 1.1 and 1.2.2 + "1.3-beta | Status": "AssumeBroken" // doesn't work in multiplayer, no longer maintained + }, + + "Split Screen": { + "ID": "Ilyaki.SplitScreen", + "~3.0.1 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals + }, + + "Stardew Hack": { + "ID": "bcmpinc.StardewHack", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "Stephan's Lots of Crops": { + "ID": "stephansstardewcrops", + "MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated + "~1.1 | Status": "AssumeBroken" // broke in SDV 1.3 (overwrites vanilla items) + }, + + "Summit Reborn": { + "ID": "KoihimeNakamura.summitreborn", + "FormerIDs": "emissaryofinfinity.summitreborn", // changed in 1.0.2 + "~1.0.2 | Status": "AssumeBroken" // broke in SDV 1.3 (runtime errors) + }, + + "Tilled Soil Decay": { + "ID": "bcmpinc.TilledSoilDecay", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "Tree Spread": { + "ID": "bcmpinc.TreeSpread", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + "Yet Another Harvest With Scythe Mod": { + "ID": "bcmpinc.HarvestWithScythe", + "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) + }, + + /********* + ** Broke circa SDV 1.2 + *********/ + "Move Faster": { + "ID": "shuaiz.MoveFasterMod", + "~1.0.1 | Status": "AssumeBroken" // doesn't do anything as of SDV 1.2.33 (bad Harmony patch?) + } + } +} diff --git a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json b/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json deleted file mode 100644 index f1e0023e..00000000 --- a/src/SMAPI.Web/wwwroot/StardewModdingAPI.metadata.json +++ /dev/null @@ -1,507 +0,0 @@ -{ - /** - * Metadata about some SMAPI mods used in compatibility, update, and dependency checks. This - * field shouldn't be edited by players in most cases. - * - * Standard fields - * =============== - * The predefined fields are documented below (only 'ID' is required). Each entry's key is the - * default display name for the mod if one isn't available (e.g. in dependency checks). - * - * - ID: the mod's latest unique ID (if any). - * - * - FormerIDs: uniquely identifies the mod across multiple versions, and supports matching - * other fields if no ID was specified. This doesn't include the latest ID, if any. Multiple - * variants can be separated with '|'. - * - * - MapLocalVersions and MapRemoteVersions correct local manifest versions and remote versions - * during update checks. For example, if the API returns version '1.1-1078' where '1078' is - * intended to be a build number, MapRemoteVersions can map it to '1.1' when comparing to the - * mod's current version. This is only meant to support legacy mods with injected update keys. - * - * Versioned metadata - * ================== - * Each record can also specify extra metadata using the field keys below. - * - * Each key consists of a field name prefixed with any combination of version range and 'Default', - * separated by pipes (whitespace trimmed). For example, 'UpdateKey' will always override, - * 'Default | UpdateKey' will only override if the mod has no update keys, and - * '~1.1 | Default | Name' will do the same up to version 1.1. - * - * The version format is 'min~max' (where either side can be blank for unbounded), or a single - * version number. - * - * These are the valid field names: - * - * - UpdateKey: the update key to set in the mod's manifest. This is used to enable update - * checks for older mods that haven't been updated to use it yet. - * - * - Status: overrides compatibility checks. The possible values are Obsolete (SMAPI won't load - * it because the mod should no longer be used), AssumeBroken (SMAPI won't load it because - * the specified version isn't compatible), or AssumeCompatible (SMAPI will try to load it - * even if it detects incompatible code). - * - * Note that this shouldn't be set to 'AssumeBroken' if SMAPI can detect the incompatibility - * automatically, since that hides the details from trace logs. - * - * - StatusReasonPhrase: a message to show to the player explaining why the mod can't be loaded - * (if applicable). If blank, will default to a generic not-compatible message. - * - * - AlternativeUrl: a URL where the player can find an unofficial update or alternative if the - * mod is no longer compatible. - */ - "ModData": { - /********* - ** Common dependencies for friendly errors - *********/ - "Advanced Location Loader": { - "ID": "Entoarox.AdvancedLocationLoader", - "Default | UpdateKey": "Nexus:2270" - }, - - //"Content Patcher": { - // "ID": "Pathoschild.ContentPatcher", - // "Default | UpdateKey": "Nexus:1915" - //}, - - //"Custom Farming Redux": { - // "ID": "Platonymous.CustomFarming", - // "Default | UpdateKey": "Nexus:991" - //}, - - "Custom Shirts": { - "ID": "Platonymous.CustomShirts", - "Default | UpdateKey": "Nexus:2416" - }, - - "Entoarox Framework": { - "ID": "Entoarox.EntoaroxFramework", - "Default | UpdateKey": "Nexus:2269" - }, - - "JSON Assets": { - "ID": "spacechase0.JsonAssets", - "Default | UpdateKey": "Nexus:1720", - "1.3.1 | Status": "AssumeBroken" // causes runtime crashes - }, - - "Mail Framework": { - "ID": "DIGUS.MailFrameworkMod", - "Default | UpdateKey": "Nexus:1536" - }, - - "MTN": { - "ID": "SgtPickles.MTN", - "Default | UpdateKey": "Nexus:2256", - "~1.2.6 | Status": "AssumeBroken" // replaces Game1.multiplayer, which breaks SMAPI's multiplayer API. - }, - - "PyTK": { - "ID": "Platonymous.Toolkit", - "Default | UpdateKey": "Nexus:1726" - }, - - "Rubydew": { - "ID": "bwdy.rubydew", - "SuppressWarnings": "UsesDynamic", // mod explicitly loads DLLs for Linux/Mac compatibility - "Default | UpdateKey": "Nexus:3656" - }, - - "SpaceCore": { - "ID": "spacechase0.SpaceCore", - "Default | UpdateKey": "Nexus:1348" - }, - - "Stardust Core": { - "ID": "Omegasis.StardustCore", - "Default | UpdateKey": "Nexus:2341" - }, - - "TMX Loader": { - "ID": "Platonymous.TMXLoader", - "Default | UpdateKey": "Nexus:1820" - }, - - - /********* - ** Map versions - *********/ - "Adjust Artisan Prices": { - "ID": "ThatNorthernMonkey.AdjustArtisanPrices", - "FormerIDs": "1e36d4ca-c7ef-4dfb-9927-d27a6c3c8bdc", // changed in 0.0.2-pathoschild-update - "MapRemoteVersions": { "0.01": "0.0.1" } - }, - - "Almighty Farming Tool": { - "ID": "439", - "MapRemoteVersions": { - "1.21": "1.2.1", - "1.22-unofficial.3.mizzion": "1.2.2-unofficial.3.mizzion" - } - }, - - "Basic Sprinkler Improved": { - "ID": "lrsk_sdvm_bsi.0117171308", - "MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated - }, - - "Better Shipping Box": { - "ID": "Kithio:BetterShippingBox", - "MapLocalVersions": { "1.0.1": "1.0.2" } - }, - - "Chefs Closet": { - "ID": "Duder.ChefsCloset", - "MapLocalVersions": { "1.3-1": "1.3" } - }, - - "Configurable Machines": { - "ID": "21da6619-dc03-4660-9794-8e5b498f5b97", - "MapLocalVersions": { "1.2-beta": "1.2" } - }, - - "Crafting Counter": { - "ID": "lolpcgaming.CraftingCounter", - "MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest - }, - - "Custom Linens": { - "ID": "Mevima.CustomLinens", - "MapRemoteVersions": { "1.1": "1.0" } // manifest not updated - }, - - "Dynamic Horses": { - "ID": "Bpendragon-DynamicHorses", - "MapRemoteVersions": { "1.2": "1.1-release" } // manifest not updated - }, - - "Dynamic Machines": { - "ID": "DynamicMachines", - "MapLocalVersions": { "1.1": "1.1.1" } - }, - - "Multiple Sprites and Portraits On Rotation (File Loading)": { - "ID": "FileLoading", - "MapLocalVersions": { "1.1": "1.12" } - }, - - "Relationship Status": { - "ID": "relationshipstatus", - "MapRemoteVersions": { "1.0.5": "1.0.4" } // not updated in manifest - }, - - "ReRegeneration": { - "ID": "lrsk_sdvm_rerg.0925160827", - "MapLocalVersions": { "1.1.2-release": "1.1.2" } - }, - - "Showcase Mod": { - "ID": "Igorious.Showcase", - "MapLocalVersions": { "0.9-500": "0.9" } - }, - - "Siv's Marriage Mod": { - "ID": "6266959802", // official version - "FormerIDs": "Siv.MarriageMod | medoli900.Siv's Marriage Mod", // 1.2.3-unofficial versions - "MapLocalVersions": { "0.0": "1.4" } - }, - - - /********* - ** Obsolete - *********/ - "Animal Mood Fix": { - "ID": "GPeters-AnimalMoodFix", - "~ | Status": "Obsolete", - "~ | StatusReasonPhrase": "the animal mood bugs were fixed in Stardew Valley 1.2." - }, - - "Colored Chests": { - "ID": "4befde5c-731c-4853-8e4b-c5cdf946805f", - "~ | Status": "Obsolete", - "~ | StatusReasonPhrase": "colored chests were added in Stardew Valley 1.1." - }, - - "Modder Serialization Utility": { - "ID": "SerializerUtils-0-1", - "~ | Status": "Obsolete", - "~ | StatusReasonPhrase": "it's no longer maintained or used." - }, - - "No Debug Mode": { - "ID": "NoDebugMode", - "~ | Status": "Obsolete", - "~ | StatusReasonPhrase": "debug mode was removed in SMAPI 1.0." - }, - - /********* - ** Broke in SDV 1.4 - *********/ - "Loved Labels": { - "ID": "Advize.LovedLabels", - "~2.2.1-unofficial.2-pathoschild | Status": "AssumeBroken" // runtime reflection errors - }, - - /********* - ** Broke in SMAPI 3.0 (runtime errors due to lifecycle changes) - *********/ - "Advancing Sprinklers": { - "ID": "warix3.advancingsprinklers", - "~1.0.0 | Status": "AssumeBroken" - }, - - "Arcade 2048": { - "ID": "Platonymous.2048", - "~1.0.6 | Status": "AssumeBroken" // possibly due to PyTK - }, - - "Arcade Snake": { - "ID": "Platonymous.Snake", - "~1.1.0 | Status": "AssumeBroken" // possibly due to PyTK - }, - - "Better Sprinklers": { - "ID": "Speeder.BetterSprinklers", - "~2.3.1-unofficial.7-pathoschild | Status": "AssumeBroken" - }, - - "Content Patcher": { - "ID": "Pathoschild.ContentPatcher", - "Default | UpdateKey": "Nexus:1915", - "~1.6.4 | Status": "AssumeBroken" - }, - - "Custom Adventure Guild Challenges": { - "ID": "DefenTheNation.CustomGuildChallenges", - "~1.8 | Status": "AssumeBroken" - }, - - "Custom Farming Redux": { - "ID": "Platonymous.CustomFarming", - "Default | UpdateKey": "Nexus:991", - "~2.10.10 | Status": "AssumeBroken" // possibly due to PyTK - }, - - "JoJaBan - Arcade Sokoban": { - "ID": "Platonymous.JoJaBan", - "~0.4.3 | Status": "AssumeBroken" // possibly due to PyTK - }, - - "Level Extender": { - "ID": "DevinLematty.LevelExtender", - "~3.1 | Status": "AssumeBroken" - }, - - "Mod Update Menu": { - "ID": "cat.modupdatemenu", - "~1.4 | Status": "AssumeBroken" - }, - - "Quick Start": { - "ID": "WuestMan.QuickStart", - "~1.5 | Status": "AssumeBroken" - }, - - "Seed Bag": { - "ID": "Platonymous.SeedBag", - "~1.2.7 | Status": "AssumeBroken" // possibly due to PyTK - }, - - /********* - ** Broke in SDV 1.3.36 - *********/ - "2cute FarmCave": { - "ID": "taintedwheat.2CuteFarmCave", - "Default | UpdateKey": "Nexus:843", - "~2.0 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - "Ace's Expanded Caves - Default Cave": { - "ID": "Acerbicon.AECdefault", - "Default | UpdateKey": "Nexus:2131", - "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - "Ace's Expanded Caves - Desert Cave": { - "ID": "Acerbicon.AECdesert", - "Default | UpdateKey": "Nexus:2131", - "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - "Ace's Expanded Caves - Ice Cave": { - "ID": "Acerbicon.AECice", - "Default | UpdateKey": "Nexus:2131", - "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - "Ace's Expanded Caves - Lava Cave": { - "ID": "Acerbicon.AEClava", - "Default | UpdateKey": "Nexus:2131", - "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - "Ace's Expanded Caves - Slime Cave": { - "ID": "Acerbicon.AECslime", - "Default | UpdateKey": "Nexus:2131", - "~1.2.2 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - "Green Pastures Farm": { - "ID": "bugbuddy.GreenPasturesFarm", - "Default | UpdateKey": "Nexus:2326", - "~1.0 | Status": "AssumeBroken" // references deleted Content/weapons.xnb - }, - - "Immersive Farm 2": { - "ID": "zander.immersivefarm2", - "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - "Karmylla's Immersive Map Edits": { - "ID": "Karmylla.ImmersiveMapEdits", - "Default | UpdateKey": "Nexus:1149", - "~2.4 | Status": "AssumeBroken" // references deleted Content/weapons.xnb - }, - - "Secret Gardens Greenhouse": { - "ID": "jessebot.secretgardens", - "Default | UpdateKey": "Nexus:3067", - "~2.0.1 | Status": "AssumeBroken" // references deleted Content/Mine.xnb - }, - - /********* - ** Broke circa SDV 1.3 - *********/ - "Canon-Friendly Dialogue Expansion": { - "ID": "gizzymo.canonfriendlyexpansion", - "~1.1.1 | Status": "AssumeBroken" // causes a save crash on certain dates - }, - - "Everytime Submarine": { - "ID": "MustafaDemirel.EverytimeSubmarine", - "~1.0.0 | Status": "AssumeBroken" // breaks player saves if their beach bridge is fixed - }, - - "Always Scroll Map": { - "ID": "bcmpinc.AlwaysScrollMap", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "Arcade Pong": { - "ID": "Platonymous.ArcadePong", - "~1.0.2 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals - }, - - "BJS Night Sounds": { - "ID": "BunnyJumps.BJSNightSounds", - "~1.0.0 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ - }, - - "Craft Counter": { - "ID": "bcmpinc.CraftCounter", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "Fishing Adjust": { - "ID": "shuaiz.FishingAdjustMod", - "~2.0.1 | Status": "AssumeBroken" // Method not found: 'Void Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase, Harmony.HarmonyMethod, Harmony.HarmonyMethod, Harmony.HarmonyMethod)' - }, - - "Fishing Automaton": { - "ID": "Drynwynn.FishingAutomaton", - "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ - }, - - "Fix Animal Tools": { - "ID": "bcmpinc.FixAnimalTools", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "Fix Scythe Exp": { - "ID": "bcmpinc.FixScytheExp", - "~0.3 | Status": "AssumeBroken" // broke in 1.3: Exception from HarmonyInstance "bcmpinc.FixScytheExp" [...] Bad label content in ILGenerator. - }, - - "Grass Growth": { - "ID": "bcmpinc.GrassGrowth", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "More Silo Storage": { - "ID": "OrneryWalrus.MoreSiloStorage", - "~1.0.1 | Status": "AssumeBroken" // broke in SDV 1.3 - }, - - "Movement Speed": { - "ID": "bcmpinc.MovementSpeed", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "No Added Flying Mine Monsters": { - "ID": "Drynwynn.NoAddedFlyingMineMonsters", - "~1.1 | Status": "AssumeBroken" // runtime errors with Harmony 1.2.0.1 in SMAPI 2.8+ - }, - - "Server Bookmarker": { - "ID": "Ilyaki.ServerBookmarker", - "~1.0.0 | Status": "AssumeBroken" // broke in Stardew Valley 1.3.29 (runtime errors) - }, - - "Skill Prestige: Cooking Adapter": { - "ID": "Alphablackwolf.CookingSkillPrestigeAdapter", - "FormerIDs": "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63", // changed circa 1.1 - "MapRemoteVersions": { "1.2.3": "1.1" } // manifest not updated - }, - - "Skull Cave Saver": { - "ID": "cantorsdust.SkullCaveSaver", - "FormerIDs": "8ac06349-26f7-4394-806c-95d48fd35774 | community.SkullCaveSaver", // changed in 1.1 and 1.2.2 - "1.3-beta | Status": "AssumeBroken" // doesn't work in multiplayer, no longer maintained - }, - - "Split Screen": { - "ID": "Ilyaki.SplitScreen", - "~3.0.1 | Status": "AssumeBroken" // broke in SMAPI 2.6-beta.16 due to reflection into SMAPI internals - }, - - "Stardew Hack": { - "ID": "bcmpinc.StardewHack", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "Stephan's Lots of Crops": { - "ID": "stephansstardewcrops", - "MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated - "~1.1 | Status": "AssumeBroken" // broke in SDV 1.3 (overwrites vanilla items) - }, - - "Summit Reborn": { - "ID": "KoihimeNakamura.summitreborn", - "FormerIDs": "emissaryofinfinity.summitreborn", // changed in 1.0.2 - "~1.0.2 | Status": "AssumeBroken" // broke in SDV 1.3 (runtime errors) - }, - - "Tilled Soil Decay": { - "ID": "bcmpinc.TilledSoilDecay", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "Tree Spread": { - "ID": "bcmpinc.TreeSpread", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - "Yet Another Harvest With Scythe Mod": { - "ID": "bcmpinc.HarvestWithScythe", - "~0.6 | Status": "AssumeBroken" // breaks newer versions of bcmpinc mods (per bcmpinc's request) - }, - - /********* - ** Broke circa SDV 1.2 - *********/ - "Move Faster": { - "ID": "shuaiz.MoveFasterMod", - "~1.0.1 | Status": "AssumeBroken" // doesn't do anything as of SDV 1.2.33 (bad Harmony patch?) - } - } -} diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 3ba3e6dd..8c925a58 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -59,10 +59,10 @@ namespace StardewModdingAPI internal static readonly string InternalFilesPath = Program.DllSearchPath; /// The file path for the SMAPI configuration file. - internal static string ApiConfigPath => Path.Combine(Constants.InternalFilesPath, "StardewModdingAPI.config.json"); + internal static string ApiConfigPath => Path.Combine(Constants.InternalFilesPath, "config.json"); /// The file path for the SMAPI metadata file. - internal static string ApiMetadataPath => Path.Combine(Constants.InternalFilesPath, "StardewModdingAPI.metadata.json"); + internal static string ApiMetadataPath => Path.Combine(Constants.InternalFilesPath, "metadata.json"); /// The filename prefix used for all SMAPI logs. internal static string LogNamePrefix { get; } = "SMAPI-"; diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json new file mode 100644 index 00000000..c04cceee --- /dev/null +++ b/src/SMAPI/SMAPI.config.json @@ -0,0 +1,77 @@ +/* + + + +This file contains advanced configuration for SMAPI. You generally shouldn't change this file. + + + +*/ +{ + /** + * The console color theme to use. The possible values are: + * - AutoDetect: SMAPI will assume a light background on Mac, and detect the background color automatically on Linux or Windows. + * - LightBackground: use darker text colors that look better on a white or light background. + * - DarkBackground: use lighter text colors that look better on a black or dark background. + */ + "ColorScheme": "AutoDetect", + + /** + * Whether SMAPI should check for newer versions of SMAPI and mods when you load the game. If new + * versions are available, an alert will be shown in the console. This doesn't affect the load + * time even if your connection is offline or slow, because it happens in the background. + */ + "CheckForUpdates": true, + + /** + * Whether to enable features intended for mod developers. Currently this only makes TRACE-level + * messages appear in the console. + */ + "DeveloperMode": true, + + /** + * Whether to add a section to the 'mod issues' list for mods which directly use potentially + * sensitive .NET APIs like file or shell access. Note that many mods do this legitimately as + * part of their normal functionality, so these warnings are meaningless without further + * investigation. When this is commented out, it'll be true for local debug builds and false + * otherwise. + */ + //"ParanoidWarnings": true, + + /** + * Whether SMAPI should show newer beta versions as an available update. When this is commented + * out, it'll be true if the current SMAPI version is beta, and false otherwise. + */ + //"UseBetaChannel": true, + + /** + * SMAPI's GitHub project name, used to perform update checks. + */ + "GitHubProjectName": "Pathoschild/SMAPI", + + /** + * The base URL for SMAPI's web API, used to perform update checks. + * Note: the protocol will be changed to http:// on Linux/Mac due to OpenSSL issues with the + * game's bundled Mono. + */ + "WebApiBaseUrl": "https://api.smapi.io", + + /** + * Whether SMAPI should log more information about the game context. + */ + "VerboseLogging": false, + + /** + * Whether to generate a 'SMAPI-latest.metadata-dump.json' file in the logs folder with the full mod + * metadata for detected mods. This is only needed when troubleshooting some cases. + */ + "DumpMetadata": false, + + /** + * The mod IDs SMAPI should ignore when performing update checks or validating update keys. + */ + "SuppressUpdateChecks": [ + "SMAPI.ConsoleCommands", + "SMAPI.SaveBackup" + ] +} diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 58a71f94..d723d954 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -42,11 +42,11 @@ - + PreserveNewest - - StardewModdingAPI.metadata.json + + SMAPI.metadata.json PreserveNewest diff --git a/src/SMAPI/StardewModdingAPI.config.json b/src/SMAPI/StardewModdingAPI.config.json deleted file mode 100644 index c04cceee..00000000 --- a/src/SMAPI/StardewModdingAPI.config.json +++ /dev/null @@ -1,77 +0,0 @@ -/* - - - -This file contains advanced configuration for SMAPI. You generally shouldn't change this file. - - - -*/ -{ - /** - * The console color theme to use. The possible values are: - * - AutoDetect: SMAPI will assume a light background on Mac, and detect the background color automatically on Linux or Windows. - * - LightBackground: use darker text colors that look better on a white or light background. - * - DarkBackground: use lighter text colors that look better on a black or dark background. - */ - "ColorScheme": "AutoDetect", - - /** - * Whether SMAPI should check for newer versions of SMAPI and mods when you load the game. If new - * versions are available, an alert will be shown in the console. This doesn't affect the load - * time even if your connection is offline or slow, because it happens in the background. - */ - "CheckForUpdates": true, - - /** - * Whether to enable features intended for mod developers. Currently this only makes TRACE-level - * messages appear in the console. - */ - "DeveloperMode": true, - - /** - * Whether to add a section to the 'mod issues' list for mods which directly use potentially - * sensitive .NET APIs like file or shell access. Note that many mods do this legitimately as - * part of their normal functionality, so these warnings are meaningless without further - * investigation. When this is commented out, it'll be true for local debug builds and false - * otherwise. - */ - //"ParanoidWarnings": true, - - /** - * Whether SMAPI should show newer beta versions as an available update. When this is commented - * out, it'll be true if the current SMAPI version is beta, and false otherwise. - */ - //"UseBetaChannel": true, - - /** - * SMAPI's GitHub project name, used to perform update checks. - */ - "GitHubProjectName": "Pathoschild/SMAPI", - - /** - * The base URL for SMAPI's web API, used to perform update checks. - * Note: the protocol will be changed to http:// on Linux/Mac due to OpenSSL issues with the - * game's bundled Mono. - */ - "WebApiBaseUrl": "https://api.smapi.io", - - /** - * Whether SMAPI should log more information about the game context. - */ - "VerboseLogging": false, - - /** - * Whether to generate a 'SMAPI-latest.metadata-dump.json' file in the logs folder with the full mod - * metadata for detected mods. This is only needed when troubleshooting some cases. - */ - "DumpMetadata": false, - - /** - * The mod IDs SMAPI should ignore when performing update checks or validating update keys. - */ - "SuppressUpdateChecks": [ - "SMAPI.ConsoleCommands", - "SMAPI.SaveBackup" - ] -} -- cgit From e18ffc009d4fd56b200b0bb13b671940c9fadbc7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 25 Apr 2019 00:50:26 -0400 Subject: update mods + mod build package for smapi-internal changes --- build/prepare-nuget-package.targets | 8 ++++---- docs/mod-build-config.md | 4 ++-- src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj | 1 + src/SMAPI.ModBuildConfig/build/smapi.targets | 14 +++++++------- src/SMAPI.ModBuildConfig/package.nuspec | 6 +++--- src/SMAPI/Constants.cs | 12 ++++++++---- 6 files changed, 25 insertions(+), 20 deletions(-) (limited to 'src/SMAPI') diff --git a/build/prepare-nuget-package.targets b/build/prepare-nuget-package.targets index 8894c273..cafaeda6 100644 --- a/build/prepare-nuget-package.targets +++ b/build/prepare-nuget-package.targets @@ -13,9 +13,9 @@ - - - - + + + + diff --git a/docs/mod-build-config.md b/docs/mod-build-config.md index fc63a5a2..aee81113 100644 --- a/docs/mod-build-config.md +++ b/docs/mod-build-config.md @@ -228,11 +228,11 @@ _[Game path](#game-path)_ above. ## Release notes ### Upcoming release -* Updated for Stardew Valley 1.4. +* Updated for SMAPI 3.0 and Stardew Valley 1.4. * If the project contains an `assets` folder, its contents are now included in the mod automatically. * Fixed `Newtonsoft.Json.pdb` included in release zips when Json.NET is referenced directly. * Fixed `` not working for `i18n` files. -* Dropped support for very old versions of SMAPI and Visual Studio. +* Dropped support for older versions of SMAPI and Visual Studio. ### 2.2 * Added support for SMAPI 2.8+ (still compatible with earlier versions). diff --git a/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj index f39a1555..0af8eef9 100644 --- a/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj +++ b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj @@ -36,5 +36,6 @@ + diff --git a/src/SMAPI.ModBuildConfig/build/smapi.targets b/src/SMAPI.ModBuildConfig/build/smapi.targets index f703477f..c8f60c65 100644 --- a/src/SMAPI.ModBuildConfig/build/smapi.targets +++ b/src/SMAPI.ModBuildConfig/build/smapi.targets @@ -2,7 +2,7 @@ - + - - - - diff --git a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs index cdc729e2..40c2d986 100644 --- a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs +++ b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Internal.ConsoleWriting { diff --git a/src/SMAPI.Internal/EnvironmentUtility.cs b/src/SMAPI.Internal/EnvironmentUtility.cs deleted file mode 100644 index c4e4678a..00000000 --- a/src/SMAPI.Internal/EnvironmentUtility.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -#if SMAPI_FOR_WINDOWS -using System.Management; -#endif -using System.Runtime.InteropServices; - -namespace StardewModdingAPI.Internal -{ - /// Provides methods for fetching environment information. - internal static class EnvironmentUtility - { - /********* - ** Fields - *********/ - /// Get the OS name from the system uname command. - /// The buffer to fill with the resulting string. - [DllImport("libc")] - static extern int uname(IntPtr buffer); - - - /********* - ** Public methods - *********/ - /// Detect the current OS. - public static Platform DetectPlatform() - { - switch (Environment.OSVersion.Platform) - { - case PlatformID.MacOSX: - return Platform.Mac; - - case PlatformID.Unix: - return EnvironmentUtility.IsRunningMac() - ? Platform.Mac - : Platform.Linux; - - default: - return Platform.Windows; - } - } - - - /// Get the human-readable OS name and version. - /// The current platform. - [SuppressMessage("ReSharper", "EmptyGeneralCatchClause", Justification = "Error suppressed deliberately to fallback to default behaviour.")] - public static string GetFriendlyPlatformName(Platform platform) - { -#if SMAPI_FOR_WINDOWS - try - { - return new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem") - .Get() - .Cast() - .Select(entry => entry.GetPropertyValue("Caption").ToString()) - .FirstOrDefault(); - } - catch { } -#endif - return (platform == Platform.Mac ? "MacOS " : "") + Environment.OSVersion; - } - - /// Get the name of the Stardew Valley executable. - /// The current platform. - public static string GetExecutableName(Platform platform) - { - return platform == Platform.Windows - ? "Stardew Valley.exe" - : "StardewValley.exe"; - } - - /// Get whether the platform uses Mono. - /// The current platform. - public static bool IsMono(this Platform platform) - { - return platform == Platform.Linux || platform == Platform.Mac; - } - - /********* - ** Private methods - *********/ - /// Detect whether the code is running on Mac. - /// - /// This code is derived from the Mono project (see System.Windows.Forms/System.Windows.Forms/XplatUI.cs). It detects Mac by calling the - /// uname system command and checking the response, which is always 'Darwin' for MacOS. - /// - private static bool IsRunningMac() - { - IntPtr buffer = IntPtr.Zero; - try - { - buffer = Marshal.AllocHGlobal(8192); - if (EnvironmentUtility.uname(buffer) == 0) - { - string os = Marshal.PtrToStringAnsi(buffer); - return os == "Darwin"; - } - return false; - } - catch - { - return false; // default to Linux - } - finally - { - if (buffer != IntPtr.Zero) - Marshal.FreeHGlobal(buffer); - } - } - } -} diff --git a/src/SMAPI.Internal/Platform.cs b/src/SMAPI.Internal/Platform.cs deleted file mode 100644 index 81ca5c1f..00000000 --- a/src/SMAPI.Internal/Platform.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace StardewModdingAPI.Internal -{ - /// The game's platform version. - internal enum Platform - { - /// The Linux version of the game. - Linux, - - /// The Mac version of the game. - Mac, - - /// The Windows version of the game. - Windows - } -} diff --git a/src/SMAPI.Internal/SMAPI.Internal.projitems b/src/SMAPI.Internal/SMAPI.Internal.projitems index 54b12003..1408cc46 100644 --- a/src/SMAPI.Internal/SMAPI.Internal.projitems +++ b/src/SMAPI.Internal/SMAPI.Internal.projitems @@ -10,9 +10,7 @@ - - \ No newline at end of file diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj index 2c6493da..2be84316 100644 --- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj +++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj @@ -18,6 +18,7 @@ + diff --git a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs new file mode 100644 index 00000000..4f67c00e --- /dev/null +++ b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs @@ -0,0 +1,113 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +#if SMAPI_FOR_WINDOWS +using System.Management; +#endif +using System.Runtime.InteropServices; + +namespace StardewModdingAPI.Toolkit.Utilities +{ + /// Provides methods for fetching environment information. + public static class EnvironmentUtility + { + /********* + ** Fields + *********/ + /// Get the OS name from the system uname command. + /// The buffer to fill with the resulting string. + [DllImport("libc")] + static extern int uname(IntPtr buffer); + + + /********* + ** Public methods + *********/ + /// Detect the current OS. + public static Platform DetectPlatform() + { + switch (Environment.OSVersion.Platform) + { + case PlatformID.MacOSX: + return Platform.Mac; + + case PlatformID.Unix: + return EnvironmentUtility.IsRunningMac() + ? Platform.Mac + : Platform.Linux; + + default: + return Platform.Windows; + } + } + + + /// Get the human-readable OS name and version. + /// The current platform. + [SuppressMessage("ReSharper", "EmptyGeneralCatchClause", Justification = "Error suppressed deliberately to fallback to default behaviour.")] + public static string GetFriendlyPlatformName(Platform platform) + { +#if SMAPI_FOR_WINDOWS + try + { + return new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem") + .Get() + .Cast() + .Select(entry => entry.GetPropertyValue("Caption").ToString()) + .FirstOrDefault(); + } + catch { } +#endif + return (platform == Platform.Mac ? "MacOS " : "") + Environment.OSVersion; + } + + /// Get the name of the Stardew Valley executable. + /// The current platform. + public static string GetExecutableName(Platform platform) + { + return platform == Platform.Windows + ? "Stardew Valley.exe" + : "StardewValley.exe"; + } + + /// Get whether the platform uses Mono. + /// The current platform. + public static bool IsMono(this Platform platform) + { + return platform == Platform.Linux || platform == Platform.Mac; + } + + + /********* + ** Private methods + *********/ + /// Detect whether the code is running on Mac. + /// + /// This code is derived from the Mono project (see System.Windows.Forms/System.Windows.Forms/XplatUI.cs). It detects Mac by calling the + /// uname system command and checking the response, which is always 'Darwin' for MacOS. + /// + private static bool IsRunningMac() + { + IntPtr buffer = IntPtr.Zero; + try + { + buffer = Marshal.AllocHGlobal(8192); + if (EnvironmentUtility.uname(buffer) == 0) + { + string os = Marshal.PtrToStringAnsi(buffer); + return os == "Darwin"; + } + return false; + } + catch + { + return false; // default to Linux + } + finally + { + if (buffer != IntPtr.Zero) + Marshal.FreeHGlobal(buffer); + } + } + } +} diff --git a/src/SMAPI.Toolkit/Utilities/Platform.cs b/src/SMAPI.Toolkit/Utilities/Platform.cs new file mode 100644 index 00000000..d64cbeb9 --- /dev/null +++ b/src/SMAPI.Toolkit/Utilities/Platform.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Toolkit.Utilities +{ + /// The game's platform version. + public enum Platform + { + /// The Linux version of the game. + Linux, + + /// The Mac version of the game. + Mac, + + /// The Windows version of the game. + Windows + } +} diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index e02c9265..4e24477b 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -5,7 +5,7 @@ using System.Reflection; using StardewModdingAPI.Enums; using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.ModLoading; -using StardewModdingAPI.Internal; +using StardewModdingAPI.Toolkit.Utilities; using StardewValley; namespace StardewModdingAPI diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index ca171ae1..8dfacc33 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -6,9 +6,9 @@ using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; using StardewModdingAPI.Framework.Exceptions; -using StardewModdingAPI.Internal; using StardewModdingAPI.Metadata; using StardewModdingAPI.Toolkit.Framework.ModData; +using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Framework.ModLoading { diff --git a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs index 01460dce..d4366294 100644 --- a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs +++ b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Mono.Cecil; -using StardewModdingAPI.Internal; +using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Framework.ModLoading { diff --git a/src/SMAPI/GamePlatform.cs b/src/SMAPI/GamePlatform.cs index 3bd74462..174239e0 100644 --- a/src/SMAPI/GamePlatform.cs +++ b/src/SMAPI/GamePlatform.cs @@ -1,4 +1,4 @@ -using StardewModdingAPI.Internal; +using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI { diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 3a34872a..df7654cd 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -7,7 +7,7 @@ using System.Threading; #if SMAPI_FOR_WINDOWS #endif using StardewModdingAPI.Framework; -using StardewModdingAPI.Internal; +using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI { -- cgit From 904c39eb7286df6ad3098dfdcfbf09cb282141e4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 18 Jun 2019 23:59:30 -0400 Subject: move assembly references out of common.targets --- build/common.targets | 71 +--------------------- .../SMAPI.Mods.ConsoleCommands.csproj | 49 +++++++++++++++ .../SMAPI.Mods.SaveBackup.csproj | 7 +++ src/SMAPI.Tests/SMAPI.Tests.csproj | 7 +++ src/SMAPI/SMAPI.csproj | 62 +++++++++++++++++++ 5 files changed, 126 insertions(+), 70 deletions(-) (limited to 'src/SMAPI') diff --git a/build/common.targets b/build/common.targets index 6bf1305e..abcf2d87 100644 --- a/build/common.targets +++ b/build/common.targets @@ -3,79 +3,10 @@ + $(AssemblySearchPaths);{GAC} $(DefineConstants);SMAPI_FOR_WINDOWS - - - - - - - $(AssemblySearchPaths);{GAC} - - - - - $(GamePath)\Stardew Valley.exe - False - - - $(GamePath)\StardewValley.GameData.dll - False - - - $(GamePath)\Netcode.dll - False - - - False - - - False - - - False - - - False - - - - - - - $(GamePath)\StardewValley.exe - False - - - $(GamePath)\StardewValley.GameData.MonoGame.dll - False - - - $(GamePath)\MonoGame.Framework.dll - False - - - - - - - $(GamePath)\GalaxyCSharp.dll - False - - - $(GamePath)\Lidgren.Network.dll - False - - - $(GamePath)\xTile.dll - False - - - - - diff --git a/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj index 13f92443..6cceb22d 100644 --- a/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj +++ b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj @@ -17,6 +17,55 @@ + + + $(GamePath)\$(GameExecutableName).exe + False + + + + + + + + + $(GamePath)\StardewValley.GameData.dll + False + + + $(GamePath)\Netcode.dll + False + + + False + + + False + + + False + + + False + + + + + + + + + $(GamePath)\StardewValley.GameData.MonoGame.dll + False + + + $(GamePath)\MonoGame.Framework.dll + False + + + + + Properties\GlobalAssemblyInfo.cs diff --git a/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj index 9375cb64..d2e41e77 100644 --- a/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj +++ b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj @@ -17,6 +17,13 @@ + + + $(GamePath)\$(GameExecutableName).exe + False + + + Properties\GlobalAssemblyInfo.cs diff --git a/src/SMAPI.Tests/SMAPI.Tests.csproj b/src/SMAPI.Tests/SMAPI.Tests.csproj index 1c414127..2f632a49 100644 --- a/src/SMAPI.Tests/SMAPI.Tests.csproj +++ b/src/SMAPI.Tests/SMAPI.Tests.csproj @@ -25,6 +25,13 @@ + + + $(GamePath)\$(GameExecutableName).exe + True + + + Properties\GlobalAssemblyInfo.cs diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index d723d954..8b7d6277 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -23,6 +23,10 @@ + + $(GamePath)\$(GameExecutableName).exe + False + True @@ -32,6 +36,64 @@ + + + + + + $(GamePath)\StardewValley.GameData.dll + False + + + $(GamePath)\Netcode.dll + False + + + False + + + False + + + False + + + False + + + + + + + + + $(GamePath)\StardewValley.GameData.MonoGame.dll + False + + + $(GamePath)\MonoGame.Framework.dll + False + + + + + + + + + $(GamePath)\GalaxyCSharp.dll + False + + + $(GamePath)\Lidgren.Network.dll + False + + + $(GamePath)\xTile.dll + False + + + -- cgit From c9778b567e3fe47a790bcf1d473a7092052a1ba3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 8 Jul 2019 17:48:20 -0400 Subject: update draw logic (#638) --- src/SMAPI/Framework/SGame.cs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 7222899a..2f642692 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -977,6 +977,13 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, color1); for (int index = 0; index < Game1.currentLightSources.Count; ++index) { + LightSource lightSource = Game1.currentLightSources.ElementAt(index); + if (lightSource.PlayerID != 0L && lightSource.PlayerID != Game1.player.UniqueMultiplayerID) + { + Farmer farmerMaybeOffline = Game1.getFarmerMaybeOffline(lightSource.PlayerID); + if (farmerMaybeOffline == null || farmerMaybeOffline.currentLocation != null && farmerMaybeOffline.currentLocation.Name != Game1.currentLocation.Name || (bool)((NetFieldBase)farmerMaybeOffline.hidden)) + continue; + } if (Utility.isOnScreen((Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position), (int)((double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) * 64.0 * 4.0))) { SpriteBatch spriteBatch = Game1.spriteBatch; @@ -1045,7 +1052,7 @@ namespace StardewModdingAPI.Framework } foreach (Farmer farmerShadow in this._farmerShadows) { - if (!(bool)((NetFieldBase)farmerShadow.swimming) && !farmerShadow.isRidingHorse() && (Game1.currentLocation == null || !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(farmerShadow.getTileLocation()))) + if (!Game1.multiplayer.isDisconnecting(farmerShadow.UniqueMultiplayerID) && !(bool)((NetFieldBase)farmerShadow.swimming) && !farmerShadow.isRidingHorse() && (Game1.currentLocation == null || !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(farmerShadow.getTileLocation()))) { SpriteBatch spriteBatch = Game1.spriteBatch; Texture2D shadowTexture = Game1.shadowTexture; @@ -1283,6 +1290,27 @@ namespace StardewModdingAPI.Framework } if (Game1.currentBillboard != 0) this.drawBillboard(); + if (!Game1.eventUp && Game1.farmEvent == null && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && Game1.isOutdoorMapSmallerThanViewport()) + { + SpriteBatch spriteBatch1 = Game1.spriteBatch; + Texture2D fadeToBlackRect1 = Game1.fadeToBlackRect; + int width1 = -Math.Min(Game1.viewport.X, 4096); + viewport = Game1.graphics.GraphicsDevice.Viewport; + int height1 = viewport.Height; + Microsoft.Xna.Framework.Rectangle destinationRectangle1 = new Microsoft.Xna.Framework.Rectangle(0, 0, width1, height1); + Color black1 = Color.Black; + spriteBatch1.Draw(fadeToBlackRect1, destinationRectangle1, black1); + SpriteBatch spriteBatch2 = Game1.spriteBatch; + Texture2D fadeToBlackRect2 = Game1.fadeToBlackRect; + int x = -Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64; + viewport = Game1.graphics.GraphicsDevice.Viewport; + int width2 = Math.Min(4096, viewport.Width - (-Game1.viewport.X + Game1.currentLocation.map.Layers[0].LayerWidth * 64)); + viewport = Game1.graphics.GraphicsDevice.Viewport; + int height2 = viewport.Height; + Microsoft.Xna.Framework.Rectangle destinationRectangle2 = new Microsoft.Xna.Framework.Rectangle(x, 0, width2, height2); + Color black2 = Color.Black; + spriteBatch2.Draw(fadeToBlackRect2, destinationRectangle2, black2); + } if ((Game1.displayHUD || Game1.eventUp) && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && (!Game1.freezeControls && !Game1.panMode && !Game1.HostPaused)) { events.RenderingHud.RaiseEmpty(); -- cgit From c6d4381142ef4e871a7b203c4c940a792bcd1a1e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 8 Jul 2019 20:59:55 -0400 Subject: update for SDV 1.4 build change on Linux/Mac (#638) --- src/SMAPI.ModBuildConfig/build/smapi.targets | 12 +++---- src/SMAPI.ModBuildConfig/package.nuspec | 2 +- .../SMAPI.Mods.ConsoleCommands.csproj | 12 +++---- src/SMAPI/SMAPI.csproj | 42 +++++++++------------- 4 files changed, 26 insertions(+), 42 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI.ModBuildConfig/build/smapi.targets b/src/SMAPI.ModBuildConfig/build/smapi.targets index 5eeea91e..78d3a3d4 100644 --- a/src/SMAPI.ModBuildConfig/build/smapi.targets +++ b/src/SMAPI.ModBuildConfig/build/smapi.targets @@ -46,6 +46,10 @@ $(GamePath)\$(GameExecutableName).exe $(CopyModReferencesToBuildOutput) + + $(GamePath)\StardewValley.GameData.dll + $(CopyModReferencesToBuildOutput) + $(GamePath)\StardewModdingAPI.exe $(CopyModReferencesToBuildOutput) @@ -82,10 +86,6 @@ $(GamePath)\Netcode.dll $(CopyModReferencesToBuildOutput) - - $(GamePath)\StardewValley.GameData.dll - $(CopyModReferencesToBuildOutput) - @@ -94,10 +94,6 @@ $(GamePath)\MonoGame.Framework.dll $(CopyModReferencesToBuildOutput) - - $(GamePath)\StardewValley.GameData.MonoGame.dll - $(CopyModReferencesToBuildOutput) - diff --git a/src/SMAPI.ModBuildConfig/package.nuspec b/src/SMAPI.ModBuildConfig/package.nuspec index ffa47fdb..76818c9f 100644 --- a/src/SMAPI.ModBuildConfig/package.nuspec +++ b/src/SMAPI.ModBuildConfig/package.nuspec @@ -2,7 +2,7 @@ Pathoschild.Stardew.ModBuildConfig - 3.0.0-beta.4 + 3.0.0-beta.6 Build package for SMAPI mods Pathoschild Pathoschild diff --git a/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj index 6cceb22d..80e1986e 100644 --- a/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj +++ b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj @@ -22,16 +22,16 @@ $(GamePath)\$(GameExecutableName).exe False + + $(GamePath)\StardewValley.GameData.dll + False + - - $(GamePath)\StardewValley.GameData.dll - False - $(GamePath)\Netcode.dll False @@ -54,10 +54,6 @@ - - $(GamePath)\StardewValley.GameData.MonoGame.dll - False - $(GamePath)\MonoGame.Framework.dll False diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 8b7d6277..994a8715 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -27,23 +27,34 @@ $(GamePath)\$(GameExecutableName).exe False + + $(GamePath)\StardewValley.GameData.dll + False + True True - + + $(GamePath)\GalaxyCSharp.dll + False + + + $(GamePath)\Lidgren.Network.dll + False + + + $(GamePath)\xTile.dll + False + - - $(GamePath)\StardewValley.GameData.dll - False - $(GamePath)\Netcode.dll False @@ -60,16 +71,13 @@ False + - - $(GamePath)\StardewValley.GameData.MonoGame.dll - False - $(GamePath)\MonoGame.Framework.dll False @@ -78,22 +86,6 @@ - - - - $(GamePath)\GalaxyCSharp.dll - False - - - $(GamePath)\Lidgren.Network.dll - False - - - $(GamePath)\xTile.dll - False - - - -- cgit From e2f545484e1a63d55154e2b6a924dfb6d94f7a5a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 12 Jul 2019 20:51:46 -0400 Subject: add asset propagation for critter textures (#652) --- docs/release-notes.md | 3 ++- src/SMAPI/Metadata/CoreAssetPropagator.cs | 34 ++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 3f955e78..49bc2eab 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -25,11 +25,12 @@ These changes have not been released yet. * Fixed outdoor tilesheets being seasonalised when added to an indoor location. * For modders: + * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised). * Added support for content pack translations. * Added `IContentPack.HasFile` method. * Added `Context.IsGameLaunched` field. - * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised). * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. + * Added asset propagation for critter textures. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. * When a mod is incompatible, the trace logs now list all detected issues instead of the first one. * Removed all deprecated APIs. diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 9e84c67f..b000d503 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -316,8 +316,12 @@ namespace StardewModdingAPI.Metadata return true; /**** - ** Content\Critters + ** Content\TileSheets ****/ + case "tilesheets\\critters": // Critter constructor + this.ReloadCritterTextures(content, key); + return true; + case "tilesheets\\crops": // Game1.LoadContent Game1.cropSpriteSheet = content.Load(key); return true; @@ -562,6 +566,34 @@ namespace StardewModdingAPI.Metadata return false; } + /// Reload critter textures. + /// The content manager through which to reload the asset. + /// The asset key to reload. + /// Returns the number of reloaded assets. + private int ReloadCritterTextures(LocalizedContentManager content, string key) + { + // get critters + Critter[] critters = + ( + from location in this.GetLocations() + let locCritters = this.Reflection.GetField>(location, "critters").GetValue() + where locCritters != null + from Critter critter in locCritters + where this.GetNormalisedPath(critter.sprite.textureName) == key + select critter + ) + .ToArray(); + if (!critters.Any()) + return 0; + + // update sprites + Texture2D texture = content.Load(key); + foreach (var entry in critters) + this.SetSpriteTexture(entry.sprite, texture); + + return critters.Length; + } + /// Reload the sprites for a fence type. /// The asset key to reload. /// Returns whether any textures were reloaded. -- cgit From 4f7d861ce4767259a556607a167481e074ec4f4c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 13 Jul 2019 22:45:48 -0400 Subject: make SemanticVersion.TryParse public --- docs/release-notes.md | 3 +-- src/SMAPI/SemanticVersion.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 49bc2eab..9980c310 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -27,8 +27,7 @@ These changes have not been released yet. * For modders: * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised). * Added support for content pack translations. - * Added `IContentPack.HasFile` method. - * Added `Context.IsGameLaunched` field. + * Added fields and methods: `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`. * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. * Added asset propagation for critter textures. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. diff --git a/src/SMAPI/SemanticVersion.cs b/src/SMAPI/SemanticVersion.cs index acdc92f8..b346cfdd 100644 --- a/src/SMAPI/SemanticVersion.cs +++ b/src/SMAPI/SemanticVersion.cs @@ -141,7 +141,7 @@ namespace StardewModdingAPI /// The version string. /// The parsed representation. /// Returns whether parsing the version succeeded. - internal static bool TryParse(string version, out ISemanticVersion parsed) + public static bool TryParse(string version, out ISemanticVersion parsed) { if (Toolkit.SemanticVersion.TryParse(version, out ISemanticVersion versionImpl)) { -- cgit From 1053232c2039a2815baf2cfa99fe8c554d1350a9 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Jul 2019 14:55:31 -0400 Subject: add asset propagation for DayTimeMoneyBox buttons --- docs/release-notes.md | 2 +- src/SMAPI/Metadata/CoreAssetPropagator.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 9980c310..404424e7 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -29,7 +29,7 @@ These changes have not been released yet. * Added support for content pack translations. * Added fields and methods: `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`. * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. - * Added asset propagation for critter textures. + * Added asset propagation for critter textures and `DayTimeMoneyBox` buttons. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. * When a mod is incompatible, the trace logs now list all detected issues instead of the first one. * Removed all deprecated APIs. diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index b000d503..3fbca04a 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -293,6 +293,11 @@ namespace StardewModdingAPI.Metadata case "loosesprites\\cursors": // Game1.LoadContent Game1.mouseCursors = content.Load(key); + foreach (DayTimeMoneyBox menu in Game1.onScreenMenus.OfType()) + { + foreach (ClickableTextureComponent button in new[] { menu.questButton, menu.zoomInButton, menu.zoomOutButton }) + button.texture = Game1.mouseCursors; + } return true; case "loosesprites\\daybg": // Game1.LoadContent -- cgit From b2134035b78c06362a4b973502e679be0b5a0de3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 17 Jul 2019 13:07:59 -0400 Subject: update NuGet packages --- docs/release-notes.md | 2 +- .../SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 6 +++--- src/SMAPI.Tests/SMAPI.Tests.csproj | 10 +++------- src/SMAPI.Toolkit/SMAPI.Toolkit.csproj | 6 +++--- src/SMAPI.Web/SMAPI.Web.csproj | 16 ++++++++-------- src/SMAPI/SMAPI.csproj | 2 +- 6 files changed, 19 insertions(+), 23 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index bc5e5a89..e22d3718 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -38,7 +38,7 @@ These changes have not been released yet. * When a mod is incompatible, the trace logs now list all detected issues instead of the first one. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. - * Updated to Json.NET 12.0.1. + * Updated to Json.NET 12.0.2. * Fixed issue where mod changes weren't tracked correctly for raising events in some cases. Events now reflect a frozen snapshot of the game state, and any mod changes are reflected in the next event tick. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index 44e7ffab..8edd5b1e 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/SMAPI.Tests/SMAPI.Tests.csproj b/src/SMAPI.Tests/SMAPI.Tests.csproj index 2f632a49..41e12d7d 100644 --- a/src/SMAPI.Tests/SMAPI.Tests.csproj +++ b/src/SMAPI.Tests/SMAPI.Tests.csproj @@ -16,13 +16,9 @@ - - - - - - - + + + diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj index 53bbe1ac..ad7ecd20 100644 --- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj +++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj @@ -15,9 +15,9 @@ - - - + + + diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj index 90641611..2f90389b 100644 --- a/src/SMAPI.Web/SMAPI.Web.csproj +++ b/src/SMAPI.Web/SMAPI.Web.csproj @@ -16,15 +16,15 @@ - - - - - - - + + + + + + + - + diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 994a8715..d518b158 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -19,7 +19,7 @@ - + -- cgit From 79622d79b8b0ef6850b9431392dc57819cb89346 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 17 Jul 2019 13:15:48 -0400 Subject: Update Mono.Cecil package --- docs/release-notes.md | 2 +- src/SMAPI/SMAPI.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index e22d3718..ea988fe5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -38,7 +38,7 @@ These changes have not been released yet. * When a mod is incompatible, the trace logs now list all detected issues instead of the first one. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. - * Updated to Json.NET 12.0.2. + * Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4). * Fixed issue where mod changes weren't tracked correctly for raising events in some cases. Events now reflect a frozen snapshot of the game state, and any mod changes are reflected in the next event tick. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index d518b158..0157e66a 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -18,7 +18,7 @@ - + -- cgit From 673ef91cc75e3b460acb8ab875d4d9d0be07042e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 20 Jul 2019 14:54:56 -0400 Subject: show versions in duplicate-mod errors, make folder paths in trace logs clearer --- docs/release-notes.md | 4 +++- src/SMAPI.Tests/Core/ModResolverTests.cs | 14 ++++++++++---- src/SMAPI/Framework/IModMetadata.cs | 10 ++++++++-- src/SMAPI/Framework/ModLoading/ModMetadata.cs | 25 +++++++++++++++++++------ src/SMAPI/Framework/ModLoading/ModResolver.cs | 12 +++++++++--- src/SMAPI/Framework/SCore.cs | 10 +++++----- 6 files changed, 54 insertions(+), 21 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 9c3e3d28..d6076b0f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,6 +12,7 @@ These changes have not been released yet. * Now ignores metadata files/folders like `__MACOSX` and `__folder_managed_by_vortex`. * Now ignores content files like `.txt` or `.png`, which avoids missing-manifest errors in some common cases. * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods. + * Duplicate-mod errors now show the mod version in each folder. * Updated mod compatibility list. * Fixed mods needing to load custom `Map` assets before the game accesses them (SMAPI will now do so automatically). * Fixed Save Backup not pruning old backups if they're uncompressed. @@ -37,7 +38,8 @@ These changes have not been released yet. * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. * Added asset propagation for critter textures and `DayTimeMoneyBox` buttons. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. - * When a mod is incompatible, the trace logs now list all detected issues instead of the first one. + * Trace logs for a broken mod now list all detected issues (instead of the first one). + * Trace logs when loading mods are now more clear. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. * Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4). diff --git a/src/SMAPI.Tests/Core/ModResolverTests.cs b/src/SMAPI.Tests/Core/ModResolverTests.cs index 4a1f04c6..ee1c0b99 100644 --- a/src/SMAPI.Tests/Core/ModResolverTests.cs +++ b/src/SMAPI.Tests/Core/ModResolverTests.cs @@ -27,7 +27,7 @@ namespace StardewModdingAPI.Tests.Core public void ReadBasicManifest_NoMods_ReturnsEmptyList() { // arrange - string rootFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + string rootFolder = this.GetTempFolderPath(); Directory.CreateDirectory(rootFolder); // act @@ -41,7 +41,7 @@ namespace StardewModdingAPI.Tests.Core public void ReadBasicManifest_EmptyModFolder_ReturnsFailedManifest() { // arrange - string rootFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + string rootFolder = this.GetTempFolderPath(); string modFolder = Path.Combine(rootFolder, Guid.NewGuid().ToString("N")); Directory.CreateDirectory(modFolder); @@ -78,7 +78,7 @@ namespace StardewModdingAPI.Tests.Core }; // write to filesystem - string rootFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + string rootFolder = this.GetTempFolderPath(); string modFolder = Path.Combine(rootFolder, Guid.NewGuid().ToString("N")); string filename = Path.Combine(modFolder, "manifest.json"); Directory.CreateDirectory(modFolder); @@ -209,7 +209,7 @@ namespace StardewModdingAPI.Tests.Core IManifest manifest = this.GetManifest(); // create DLL - string modFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); + string modFolder = Path.Combine(this.GetTempFolderPath(), Guid.NewGuid().ToString("N")); Directory.CreateDirectory(modFolder); File.WriteAllText(Path.Combine(modFolder, manifest.EntryDll), ""); @@ -462,6 +462,12 @@ namespace StardewModdingAPI.Tests.Core /********* ** Private methods *********/ + /// Get a generated folder path in the temp folder. This folder isn't created automatically. + private string GetTempFolderPath() + { + return Path.Combine(Path.GetTempPath(), "smapi-unit-tests", Guid.NewGuid().ToString("N")); + } + /// Get a randomised basic manifest. /// The value, or null for a generated value. /// The value, or null for a generated value. diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs index 32870c2a..6ee7df69 100644 --- a/src/SMAPI/Framework/IModMetadata.cs +++ b/src/SMAPI/Framework/IModMetadata.cs @@ -16,10 +16,13 @@ namespace StardewModdingAPI.Framework /// The mod's display name. string DisplayName { get; } - /// The mod's full directory path. + /// The root path containing mods. + string RootPath { get; } + + /// The mod's full directory path within the . string DirectoryPath { get; } - /// The relative to the game's Mods folder. + /// The relative to the . string RelativeDirectoryPath { get; } /// Metadata about the mod from SMAPI's internal data (if any). @@ -108,5 +111,8 @@ namespace StardewModdingAPI.Framework /// Get whether the mod has a given warning and it hasn't been suppressed in the . /// The warning to check. bool HasUnsuppressWarning(ModWarning warning); + + /// Get a relative path which includes the root folder name. + string GetRelativePathWithRoot(); } } diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index 39f2f482..7f788d17 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Framework.UpdateData; +using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Framework.ModLoading { @@ -17,10 +19,13 @@ namespace StardewModdingAPI.Framework.ModLoading /// The mod's display name. public string DisplayName { get; } - /// The mod's full directory path. + /// The root path containing mods. + public string RootPath { get; } + + /// The mod's full directory path within the . public string DirectoryPath { get; } - /// The relative to the game's Mods folder. + /// The relative to the . public string RelativeDirectoryPath { get; } /// The mod manifest. @@ -68,16 +73,17 @@ namespace StardewModdingAPI.Framework.ModLoading *********/ /// Construct an instance. /// The mod's display name. - /// The mod's full directory path. - /// The relative to the game's Mods folder. + /// The mod's full directory path within the . + /// The root path containing mods. /// The mod manifest. /// Metadata about the mod from SMAPI's internal data (if any). /// Whether the mod folder should be ignored. This should be true if it was found within a folder whose name starts with a dot. - public ModMetadata(string displayName, string directoryPath, string relativeDirectoryPath, IManifest manifest, ModDataRecordVersionedFields dataRecord, bool isIgnored) + public ModMetadata(string displayName, string directoryPath, string rootPath, IManifest manifest, ModDataRecordVersionedFields dataRecord, bool isIgnored) { this.DisplayName = displayName; this.DirectoryPath = directoryPath; - this.RelativeDirectoryPath = relativeDirectoryPath; + this.RootPath = rootPath; + this.RelativeDirectoryPath = PathUtilities.GetRelativePath(this.RootPath, this.DirectoryPath); this.Manifest = manifest; this.DataRecord = dataRecord; this.IsIgnored = isIgnored; @@ -196,5 +202,12 @@ namespace StardewModdingAPI.Framework.ModLoading this.Warnings.HasFlag(warning) && (this.DataRecord?.DataRecord == null || !this.DataRecord.DataRecord.SuppressWarnings.HasFlag(warning)); } + + /// Get a relative path which includes the root folder name. + public string GetRelativePathWithRoot() + { + string rootFolderName = Path.GetFileName(this.RootPath) ?? ""; + return Path.Combine(rootFolderName, this.RelativeDirectoryPath); + } } } diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index b6bdb357..20941a5f 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -42,9 +42,8 @@ namespace StardewModdingAPI.Framework.ModLoading ModMetadataStatus status = folder.ManifestParseError == ModParseError.None || shouldIgnore ? ModMetadataStatus.Found : ModMetadataStatus.Failed; - string relativePath = PathUtilities.GetRelativePath(rootPath, folder.Directory.FullName); - yield return new ModMetadata(folder.DisplayName, folder.Directory.FullName, relativePath, manifest, dataRecord, isIgnored: shouldIgnore) + yield return new ModMetadata(folder.DisplayName, folder.Directory.FullName, rootPath, manifest, dataRecord, isIgnored: shouldIgnore) .SetStatus(status, shouldIgnore ? "disabled by dot convention" : folder.ManifestParseErrorText); } } @@ -199,7 +198,14 @@ namespace StardewModdingAPI.Framework.ModLoading { if (mod.Status == ModMetadataStatus.Failed) continue; // don't replace metadata error - mod.SetStatus(ModMetadataStatus.Failed, $"you have multiple copies of this mod installed ({string.Join(", ", group.Select(p => p.RelativeDirectoryPath).OrderBy(p => p))})."); + + string folderList = string.Join(", ", + from entry in @group + let relativePath = entry.GetRelativePathWithRoot() + orderby relativePath + select $"{relativePath} ({entry.Manifest.Version})" + ); + mod.SetStatus(ModMetadataStatus.Failed, $"you have multiple copies of this mod installed. Found in folders: {folderList}."); } } } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 60deed70..0aae3b84 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -400,7 +400,7 @@ namespace StardewModdingAPI.Framework // filter out ignored mods foreach (IModMetadata mod in mods.Where(p => p.IsIgnored)) - this.Monitor.Log($" Skipped {mod.RelativeDirectoryPath} (folder name starts with a dot).", LogLevel.Trace); + this.Monitor.Log($" Skipped {mod.GetRelativePathWithRoot()} (folder name starts with a dot).", LogLevel.Trace); mods = mods.Where(p => !p.IsIgnored).ToArray(); // load mods @@ -902,13 +902,13 @@ namespace StardewModdingAPI.Framework // log entry { - string relativePath = PathUtilities.GetRelativePath(this.ModsPath, mod.DirectoryPath); + string relativePath = mod.GetRelativePathWithRoot(); if (mod.IsContentPack) - this.Monitor.Log($" {mod.DisplayName} ({relativePath}) [content pack]...", LogLevel.Trace); + this.Monitor.Log($" {mod.DisplayName} (from {relativePath}) [content pack]...", LogLevel.Trace); else if (mod.Manifest?.EntryDll != null) - this.Monitor.Log($" {mod.DisplayName} ({relativePath}{Path.DirectorySeparatorChar}{mod.Manifest.EntryDll})...", LogLevel.Trace); // don't use Path.Combine here, since EntryDLL might not be valid + this.Monitor.Log($" {mod.DisplayName} (from {relativePath}{Path.DirectorySeparatorChar}{mod.Manifest.EntryDll})...", LogLevel.Trace); // don't use Path.Combine here, since EntryDLL might not be valid else - this.Monitor.Log($" {mod.DisplayName} ({relativePath})...", LogLevel.Trace); + this.Monitor.Log($" {mod.DisplayName} (from {relativePath})...", LogLevel.Trace); } // add warning for missing update key -- cgit From dc1c9bf036ad61cbddd3390bbc2044b5f3ebd5aa Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 21 Jul 2019 22:01:23 -0400 Subject: normalise custom map's tilesheet paths for the OS --- docs/release-notes.md | 1 + .../Framework/ContentManagers/ModContentManager.cs | 53 ++++++++++++++-------- 2 files changed, 35 insertions(+), 19 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index d6076b0f..58114dde 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -40,6 +40,7 @@ These changes have not been released yet. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. * Trace logs for a broken mod now list all detected issues (instead of the first one). * Trace logs when loading mods are now more clear. + * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalised for the OS automatically. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. * Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4). diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index 2c73e861..de05e92d 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -117,7 +117,9 @@ namespace StardewModdingAPI.Framework.ContentManagers { // XNB file case ".xnb": - return this.RawLoad(assetName, useCache: false); + { + return this.RawLoad(assetName, useCache: false); + } // unpacked data case ".json": @@ -129,29 +131,34 @@ namespace StardewModdingAPI.Framework.ContentManagers // unpacked image case ".png": - // validate - if (typeof(T) != typeof(Texture2D)) - throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}'."); - - // fetch & cache - using (FileStream stream = File.OpenRead(file.FullName)) { - Texture2D texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, stream); - texture = this.PremultiplyTransparency(texture); - return (T)(object)texture; + // validate + if (typeof(T) != typeof(Texture2D)) + throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}'."); + + // fetch & cache + using (FileStream stream = File.OpenRead(file.FullName)) + { + Texture2D texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, stream); + texture = this.PremultiplyTransparency(texture); + return (T)(object)texture; + } } // unpacked map case ".tbin": - // validate - if (typeof(T) != typeof(Map)) - throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Map)}'."); - - // fetch & cache - FormatManager formatManager = FormatManager.Instance; - Map map = formatManager.LoadMap(file.FullName); - this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); - return (T)(object)map; + { + // validate + if (typeof(T) != typeof(Map)) + throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Map)}'."); + + // fetch & cache + FormatManager formatManager = FormatManager.Instance; + Map map = formatManager.LoadMap(file.FullName); + this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); + this.NormaliseTilesheetPaths(map); + return (T)(object)map; + } default: throw GetContentError($"unknown file extension '{file.Extension}'; must be one of '.json', '.png', '.tbin', or '.xnb'."); @@ -232,6 +239,14 @@ namespace StardewModdingAPI.Framework.ContentManagers return texture; } + /// Normalise map tilesheet paths for the current platform. + /// The map whose tilesheets to fix. + private void NormaliseTilesheetPaths(Map map) + { + foreach (TileSheet tilesheet in map.TileSheets) + tilesheet.ImageSource = this.NormalisePathSeparators(tilesheet.ImageSource); + } + /// Fix custom map tilesheet paths so they can be found by the content manager. /// The map whose tilesheets to fix. /// The relative map path within the mod folder. -- cgit From 4b9ba35a194ac711d7c36943fc7277ce2a33b141 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 21 Jul 2019 22:05:47 -0400 Subject: apply tilesheet fixes to XNB map files too --- docs/release-notes.md | 1 + src/SMAPI/Framework/ContentManagers/ModContentManager.cs | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 58114dde..abc08e16 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -40,6 +40,7 @@ These changes have not been released yet. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. * Trace logs for a broken mod now list all detected issues (instead of the first one). * Trace logs when loading mods are now more clear. + * Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted. * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalised for the OS automatically. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index de05e92d..d6eb28c8 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -118,7 +118,13 @@ namespace StardewModdingAPI.Framework.ContentManagers // XNB file case ".xnb": { - return this.RawLoad(assetName, useCache: false); + T data = this.RawLoad(assetName, useCache: false); + if (data is Map map) + { + this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); + this.NormaliseTilesheetPaths(map); + } + return data; } // unpacked data -- cgit From 4fb16abfe9f300b0d841a98b462967b7ca1dcbe5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 22 Jul 2019 12:44:35 -0400 Subject: normalise map tilesheets before custom-tilesheet changes to avoid errors --- src/SMAPI/Framework/ContentManagers/ModContentManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index d6eb28c8..34cabefc 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -121,8 +121,8 @@ namespace StardewModdingAPI.Framework.ContentManagers T data = this.RawLoad(assetName, useCache: false); if (data is Map map) { - this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); this.NormaliseTilesheetPaths(map); + this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); } return data; } @@ -161,8 +161,8 @@ namespace StardewModdingAPI.Framework.ContentManagers // fetch & cache FormatManager formatManager = FormatManager.Instance; Map map = formatManager.LoadMap(file.FullName); - this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); this.NormaliseTilesheetPaths(map); + this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); return (T)(object)map; } -- cgit From 8e0ddd1d00e3d0d11fbaa0ffce804b3e7186c254 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 1 Aug 2019 00:47:24 -0400 Subject: update for disconnection change in SDV 1.4 (#638) --- 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 2f642692..376368d6 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -190,7 +190,7 @@ namespace StardewModdingAPI.Framework /// This overrides the logic in to let SMAPI clean up before exit. protected override void OnExiting(object sender, EventArgs args) { - Game1.multiplayer.Disconnect(); + Game1.multiplayer.Disconnect(StardewValley.Multiplayer.DisconnectType.ClosedGame); this.OnGameExiting?.Invoke(); } -- cgit From fd77ae93d59222d70c86aebfc044f3af11063372 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 9 Aug 2019 01:18:05 -0400 Subject: fix typos and inconsistent spelling --- .gitattributes | 2 +- docs/release-notes.md | 49 ++++---- src/SMAPI.Installer/InteractiveInstaller.cs | 12 +- src/SMAPI.Installer/Program.cs | 2 +- .../ConsoleWriting/ColorfulConsoleWriter.cs | 2 +- .../Mock/Netcode/NetFieldBase.cs | 2 +- .../NetFieldAnalyzer.cs | 8 +- .../ObsoleteFieldAnalyzer.cs | 2 +- .../Framework/ModFileManager.cs | 4 +- .../Framework/Commands/Player/AddCommand.cs | 2 +- .../Framework/Commands/Player/ListItemsCommand.cs | 4 +- .../Framework/Commands/World/SetTimeCommand.cs | 2 +- src/SMAPI.Tests/Core/ModResolverTests.cs | 12 +- src/SMAPI.Tests/Core/TranslationTests.cs | 2 +- src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs | 6 +- src/SMAPI.Tests/Utilities/SemanticVersionTests.cs | 8 +- .../ISemanticVersion.cs | 2 +- .../Clients/WebApi/ModExtendedMetadataModel.cs | 4 +- .../Framework/Clients/WebApi/ModSeachModel.cs | 2 +- .../Clients/WebApi/ModSearchEntryModel.cs | 2 +- .../Framework/Clients/WebApi/WebApiClient.cs | 2 +- .../Framework/GameScanning/GameScanner.cs | 2 +- .../Framework/ModData/ModDataModel.cs | 4 +- .../Framework/ModData/ModDataRecord.cs | 6 +- .../ModData/ModDataRecordVersionedFields.cs | 4 +- src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs | 4 +- .../Framework/ModScanning/ModFolder.cs | 2 +- .../Framework/ModScanning/ModScanner.cs | 6 +- src/SMAPI.Toolkit/ModToolkit.cs | 2 +- src/SMAPI.Toolkit/SemanticVersion.cs | 24 ++-- .../Converters/ManifestContentPackForConverter.cs | 50 -------- .../Converters/ManifestDependencyArrayConverter.cs | 60 --------- .../Converters/SemanticVersionConverter.cs | 86 ------------- .../Converters/SimpleReadOnlyConverter.cs | 76 ------------ .../Serialisation/InternalExtensions.cs | 21 ---- src/SMAPI.Toolkit/Serialisation/JsonHelper.cs | 136 --------------------- src/SMAPI.Toolkit/Serialisation/Models/Manifest.cs | 74 ----------- .../Serialisation/Models/ManifestContentPackFor.cs | 15 --- .../Serialisation/Models/ManifestDependency.cs | 35 ------ src/SMAPI.Toolkit/Serialisation/SParseException.cs | 17 --- .../Converters/ManifestContentPackForConverter.cs | 50 ++++++++ .../Converters/ManifestDependencyArrayConverter.cs | 60 +++++++++ .../Converters/SemanticVersionConverter.cs | 86 +++++++++++++ .../Converters/SimpleReadOnlyConverter.cs | 76 ++++++++++++ .../Serialization/InternalExtensions.cs | 21 ++++ src/SMAPI.Toolkit/Serialization/JsonHelper.cs | 136 +++++++++++++++++++++ src/SMAPI.Toolkit/Serialization/Models/Manifest.cs | 74 +++++++++++ .../Serialization/Models/ManifestContentPackFor.cs | 15 +++ .../Serialization/Models/ManifestDependency.cs | 35 ++++++ src/SMAPI.Toolkit/Serialization/SParseException.cs | 17 +++ src/SMAPI.Toolkit/Utilities/PathUtilities.cs | 20 +-- src/SMAPI.Web/BackgroundService.cs | 6 +- .../Controllers/JsonValidatorController.cs | 14 +-- src/SMAPI.Web/Controllers/ModsApiController.cs | 2 +- .../Framework/AllowLargePostsAttribute.cs | 2 +- .../Framework/Caching/Mods/ModCacheRepository.cs | 10 +- .../Caching/UtcDateTimeOffsetSerializer.cs | 2 +- .../Framework/JobDashboardAuthorizationFilter.cs | 4 +- src/SMAPI.Web/Framework/LogParsing/LogParser.cs | 2 +- .../Framework/ModRepositories/BaseRepository.cs | 6 +- .../ModRepositories/ChucklefishRepository.cs | 2 +- .../Framework/ModRepositories/GitHubRepository.cs | 2 +- .../Framework/ModRepositories/NexusRepository.cs | 2 +- src/SMAPI.Web/Startup.cs | 2 +- src/SMAPI.Web/ViewModels/LogParserModel.cs | 2 +- src/SMAPI.Web/wwwroot/Content/js/json-validator.js | 2 +- src/SMAPI.Web/wwwroot/schemas/content-patcher.json | 6 +- src/SMAPI.sln.DotSettings | 42 +++++++ src/SMAPI/Context.cs | 4 +- src/SMAPI/Enums/LoadStage.cs | 10 +- src/SMAPI/Events/IGameLoopEvents.cs | 4 +- src/SMAPI/Events/IModEvents.cs | 4 +- src/SMAPI/Events/ISpecialisedEvents.cs | 4 +- src/SMAPI/Events/LoadStageChangedEventArgs.cs | 2 +- .../Events/UnvalidatedUpdateTickedEventArgs.cs | 2 +- .../Events/UnvalidatedUpdateTickingEventArgs.cs | 2 +- src/SMAPI/Framework/CommandManager.cs | 14 +-- src/SMAPI/Framework/Content/AssetData.cs | 10 +- .../Framework/Content/AssetDataForDictionary.cs | 10 +- src/SMAPI/Framework/Content/AssetDataForImage.cs | 10 +- src/SMAPI/Framework/Content/AssetDataForObject.cs | 20 +-- src/SMAPI/Framework/Content/AssetInfo.cs | 22 ++-- src/SMAPI/Framework/Content/ContentCache.cs | 30 ++--- src/SMAPI/Framework/ContentCoordinator.cs | 8 +- .../ContentManagers/BaseContentManager.cs | 34 +++--- .../ContentManagers/GameContentManager.cs | 58 ++++----- .../Framework/ContentManagers/IContentManager.cs | 10 +- .../Framework/ContentManagers/ModContentManager.cs | 28 ++--- src/SMAPI/Framework/ContentPack.cs | 10 +- src/SMAPI/Framework/Events/EventManager.cs | 18 +-- src/SMAPI/Framework/Events/ModEvents.cs | 6 +- src/SMAPI/Framework/Events/ModGameLoopEvents.cs | 2 +- src/SMAPI/Framework/Events/ModSpecialisedEvents.cs | 6 +- src/SMAPI/Framework/GameVersion.cs | 2 +- src/SMAPI/Framework/InternalExtensions.cs | 2 +- src/SMAPI/Framework/ModHelpers/ContentHelper.cs | 14 +-- .../Framework/ModHelpers/ContentPackHelper.cs | 4 +- src/SMAPI/Framework/ModHelpers/DataHelper.cs | 12 +- src/SMAPI/Framework/ModHelpers/ModHelper.cs | 4 +- .../Framework/ModHelpers/ModRegistryHelper.cs | 4 +- src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs | 2 +- src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 10 +- .../Framework/ModLoading/Finders/TypeFinder.cs | 2 +- .../ModLoading/InstructionHandleResult.cs | 4 +- .../Framework/ModLoading/ModDependencyStatus.cs | 4 +- src/SMAPI/Framework/ModLoading/ModResolver.cs | 8 +- .../Framework/ModLoading/TypeReferenceComparer.cs | 2 +- src/SMAPI/Framework/ModRegistry.cs | 6 +- src/SMAPI/Framework/Monitor.cs | 2 +- src/SMAPI/Framework/Networking/MessageType.cs | 2 +- src/SMAPI/Framework/Reflection/Reflector.cs | 2 +- src/SMAPI/Framework/SCore.cs | 56 ++++----- src/SMAPI/Framework/SGame.cs | 50 ++++---- src/SMAPI/Framework/SGameConstructorHack.cs | 4 +- src/SMAPI/Framework/SMultiplayer.cs | 20 +-- .../Framework/Serialisation/ColorConverter.cs | 47 ------- .../Framework/Serialisation/PointConverter.cs | 43 ------- .../Framework/Serialisation/RectangleConverter.cs | 52 -------- .../Framework/Serialization/ColorConverter.cs | 47 +++++++ .../Framework/Serialization/PointConverter.cs | 43 +++++++ .../Framework/Serialization/RectangleConverter.cs | 52 ++++++++ .../FieldWatchers/ComparableListWatcher.cs | 2 +- src/SMAPI/IAssetInfo.cs | 6 +- src/SMAPI/IContentHelper.cs | 4 +- src/SMAPI/IContentPack.cs | 2 +- src/SMAPI/IContentPackHelper.cs | 2 +- src/SMAPI/IDataHelper.cs | 2 +- src/SMAPI/Metadata/CoreAssetPropagator.cs | 42 +++---- src/SMAPI/Metadata/InstructionMetadata.cs | 10 +- src/SMAPI/Mod.cs | 2 +- src/SMAPI/Program.cs | 4 +- src/SMAPI/SemanticVersion.cs | 4 +- src/SMAPI/Translation.cs | 4 +- src/SMAPI/Utilities/SDate.cs | 6 +- 134 files changed, 1207 insertions(+), 1164 deletions(-) delete mode 100644 src/SMAPI.Toolkit/Serialisation/Converters/ManifestContentPackForConverter.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/Converters/ManifestDependencyArrayConverter.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/Converters/SimpleReadOnlyConverter.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/InternalExtensions.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/JsonHelper.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/Models/Manifest.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/Models/ManifestDependency.cs delete mode 100644 src/SMAPI.Toolkit/Serialisation/SParseException.cs create mode 100644 src/SMAPI.Toolkit/Serialization/Converters/ManifestContentPackForConverter.cs create mode 100644 src/SMAPI.Toolkit/Serialization/Converters/ManifestDependencyArrayConverter.cs create mode 100644 src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs create mode 100644 src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs create mode 100644 src/SMAPI.Toolkit/Serialization/InternalExtensions.cs create mode 100644 src/SMAPI.Toolkit/Serialization/JsonHelper.cs create mode 100644 src/SMAPI.Toolkit/Serialization/Models/Manifest.cs create mode 100644 src/SMAPI.Toolkit/Serialization/Models/ManifestContentPackFor.cs create mode 100644 src/SMAPI.Toolkit/Serialization/Models/ManifestDependency.cs create mode 100644 src/SMAPI.Toolkit/Serialization/SParseException.cs delete mode 100644 src/SMAPI/Framework/Serialisation/ColorConverter.cs delete mode 100644 src/SMAPI/Framework/Serialisation/PointConverter.cs delete mode 100644 src/SMAPI/Framework/Serialisation/RectangleConverter.cs create mode 100644 src/SMAPI/Framework/Serialization/ColorConverter.cs create mode 100644 src/SMAPI/Framework/Serialization/PointConverter.cs create mode 100644 src/SMAPI/Framework/Serialization/RectangleConverter.cs (limited to 'src/SMAPI') diff --git a/.gitattributes b/.gitattributes index 67d0626d..1161a204 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ -# normalise line endings +# normalize line endings * text=auto README.txt text=crlf diff --git a/docs/release-notes.md b/docs/release-notes.md index e253c3c0..5f964cfd 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -29,6 +29,7 @@ These changes have not been released yet. * Fixed map reloads resetting tilesheet seasons. * Fixed map reloads not updating door warps. * Fixed outdoor tilesheets being seasonalised when added to an indoor location. + * Fixed typos and inconsistent spelling. * For the mod compatibility list: * Now loads faster (since data is fetched in a background service). @@ -43,7 +44,7 @@ These changes have not been released yet. * Added support for referencing a schema in a JSON Schema-compatible text editor. * For modders: - * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialised when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialised). + * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialized when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialized). * Added support for content pack translations. * Added fields and methods: `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`. * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. @@ -53,7 +54,7 @@ These changes have not been released yet. * Trace logs when loading mods are now more clear. * Clarified update-check errors for mods with multiple update keys. * Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted. - * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalised for the OS automatically. + * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalized for the OS automatically. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. * Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4). @@ -73,7 +74,7 @@ Released 13 September 2019 for Stardew Valley 1.3.36. * For the web UI: * When filtering the mod list, clicking a mod link now automatically adds it to the visible mods. * Added log parser instructions for Android. - * Fixed log parser failing in some cases due to time format localisation. + * Fixed log parser failing in some cases due to time format localization. * For modders: * `this.Monitor.Log` now defaults to the `Trace` log level instead of `Debug`. The change will only take effect when you recompile the mod. @@ -141,12 +142,12 @@ Released 09 January 2019 for Stardew Valley 1.3.32–33. * Added locale to context trace logs. * Fixed error loading custom map tilesheets in some cases. * Fixed error when swapping maps mid-session for a location with interior doors. - * Fixed `Constants.SaveFolderName` and `CurrentSavePath` not available during early load stages when using `Specialised.LoadStageChanged` event. + * Fixed `Constants.SaveFolderName` and `CurrentSavePath` not available during early load stages when using `Specialized.LoadStageChanged` event. * Fixed `LoadStage.SaveParsed` raised before the parsed save data is available. * Fixed 'unknown mod' deprecation warnings showing the wrong stack trace. * Fixed `e.Cursor` in input events showing wrong grab tile when player using a controller moves without moving the viewpoint. - * Fixed incorrect 'bypassed safety checks' warning for mods using the new `Specialised.LoadStageChanged` event in 2.10. - * Deprecated `EntryDll` values whose capitalisation don't match the actual file. (This works on Windows, but causes errors for Linux/Mac players.) + * Fixed incorrect 'bypassed safety checks' warning for mods using the new `Specialized.LoadStageChanged` event in 2.10. + * Deprecated `EntryDll` values whose capitalization don't match the actual file. (This works on Windows, but causes errors for Linux/Mac players.) ## 2.10.1 Released 30 December 2018 for Stardew Valley 1.3.32–33. @@ -163,9 +164,9 @@ Released 29 December 2018 for Stardew Valley 1.3.32–33. * Tweaked installer to reduce antivirus false positives. * For modders: - * Added [events](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Events): `GameLoop.OneSecondUpdateTicking`, `GameLoop.OneSecondUpdateTicked`, and `Specialised.LoadStageChanged`. + * Added [events](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Events): `GameLoop.OneSecondUpdateTicking`, `GameLoop.OneSecondUpdateTicked`, and `Specialized.LoadStageChanged`. * Added `e.IsCurrentLocation` event arg to `World` events. - * You can now use `helper.Data.Read/WriteSaveData` as soon as the save is loaded (instead of once the world is initialised). + * You can now use `helper.Data.Read/WriteSaveData` as soon as the save is loaded (instead of once the world is initialized). * Increased deprecation levels to _info_ for the upcoming SMAPI 3.0. * For the web UI: @@ -338,7 +339,7 @@ Released 14 August 2018 for Stardew Valley 1.3.28. * dialogue; * map tilesheets. * Added `--mods-path` CLI command-line argument to switch between mod folders. - * All enums are now JSON-serialised by name instead of numeric value. (Previously only a few enums were serialised that way. JSON files which already have numeric enum values will still be parsed fine.) + * All enums are now JSON-serialized by name instead of numeric value. (Previously only a few enums were serialized that way. JSON files which already have numeric enum values will still be parsed fine.) * Fixed false compatibility error when constructing multidimensional arrays. * Fixed `.ToSButton()` methods not being public. @@ -365,7 +366,7 @@ Released 01 August 2018 for Stardew Valley 1.3.27. * Improved the Console Commands mod: * Added `player_add name`, which adds items to your inventory by name instead of ID. * Fixed `world_setseason` not running season-change logic. - * Fixed `world_setseason` not normalising the season value. + * Fixed `world_setseason` not normalizing the season value. * Fixed `world_settime` sometimes breaking NPC schedules (e.g. so they stay in bed). * Removed the `player_setlevel` and `player_setspeed` commands, which weren't implemented in a useful way. Use a mod like CJB Cheats Menu if you need those. * Fixed `SEHException` errors for some players. @@ -456,7 +457,7 @@ Released 11 April 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed mod update alerts not shown if one mod has an invalid remote version. * Fixed SMAPI update alerts linking to the GitHub repository instead of [smapi.io](https://smapi.io). * Fixed SMAPI update alerts for draft releases. - * Fixed error when two content packs use different capitalisation for the same required mod ID. + * Fixed error when two content packs use different capitalization for the same required mod ID. * Fixed rare crash if the game duplicates an item. * For the [log parser](https://log.smapi.io): @@ -531,8 +532,8 @@ Released 24 February 2018 for Stardew Valley 1.2.30–1.2.33. * For modders: * Added support for content packs and new APIs to read them. * Added support for `ISemanticVersion` in JSON models. - * Added `SpecialisedEvents.UnvalidatedUpdateTick` event for specialised use cases. - * Added path normalising to `ReadJsonFile` and `WriteJsonFile` helpers (so no longer need `Path.Combine` with those). + * Added `SpecializedEvents.UnvalidatedUpdateTick` event for specialized use cases. + * Added path normalizing to `ReadJsonFile` and `WriteJsonFile` helpers (so no longer need `Path.Combine` with those). * Fixed deadlock in rare cases with asset loaders. * Fixed unhelpful error when a mod exposes a non-public API. * Fixed unhelpful error when a translation file has duplicate keys due to case-insensitivity. @@ -585,11 +586,11 @@ Released 26 December 2017 for Stardew Valley 1.2.30–1.2.33. * For modders: * **Added mod-provided APIs** to allow simple integrations between mods, even without direct assembly references. - * Added `GameEvents.FirstUpdateTick` event (called once after all mods are initialised). + * Added `GameEvents.FirstUpdateTick` event (called once after all mods are initialized). * Added `IsSuppressed` to input events so mods can optionally avoid handling keys another mod has already handled. * Added trace message for mods with no update keys. * Adjusted reflection API to match actual usage (e.g. renamed `GetPrivate*` to `Get*`), and deprecated previous methods. - * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. + * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialized cases. * Fixed reflection API error for properties missing a `get` and `set`. * Fixed issue where a mod could change the cursor position reported to other mods. * Updated compatibility list. @@ -614,7 +615,7 @@ Released 02 December 2017 for Stardew Valley 1.2.30–1.2.33. * Slightly improved the UI. * For modders: - * Added `helper.Content.NormaliseAssetName` method. + * Added `helper.Content.NormalizeAssetName` method. * Added `SDate.DaysSinceStart` property. * Fixed input events' `e.SuppressButton(button)` method ignoring specified button. * Fixed input events' `e.SuppressButton()` method not working with mouse buttons. @@ -769,7 +770,7 @@ For mod developers: * Added content helper properties for the game's current language. * Fixed `Context.IsPlayerFree` being false if the player is performing an action. * Fixed `GraphicsEvents.Resize` being raised before the game updates its window data. -* Fixed `SemanticVersion` not being deserialisable through Json.NET. +* Fixed `SemanticVersion` not being deserializable through Json.NET. * Fixed terminal not launching on Xfce Linux. For SMAPI developers: @@ -840,7 +841,7 @@ For modders: * SMAPI now automatically fixes tilesheet references for maps loaded from the mod folder. _When loading a map from the mod folder, SMAPI will automatically use tilesheets relative to the map file if they exists. Otherwise it will default to tilesheets in the game content._ * Added `Context.IsPlayerFree` for mods that need to check if the player can act (i.e. save is loaded, no menu is displayed, no cutscene is in progress, etc). -* Added `Context.IsInDrawLoop` for specialised mods. +* Added `Context.IsInDrawLoop` for specialized mods. * Fixed `smapi-crash.txt` being copied from the default log even if a different path is specified with `--log-path`. * Fixed the content API not matching XNB filenames with two dots (like `a.b.xnb`) if you don't specify the `.xnb` extension. * Fixed `debug` command output not printed to console. @@ -867,7 +868,7 @@ For players: For mod developers: * Added a `Context.IsWorldReady` flag for mods to use. - _This indicates whether a save is loaded and the world is finished initialising, which starts at the same point that `SaveEvents.AfterLoad` and `TimeEvents.AfterDayStarted` are raised. This is mainly useful for events which can be raised before the world is loaded (like update tick)._ + _This indicates whether a save is loaded and the world is finished initializing, which starts at the same point that `SaveEvents.AfterLoad` and `TimeEvents.AfterDayStarted` are raised. This is mainly useful for events which can be raised before the world is loaded (like update tick)._ * Added a `debug` console command which lets you run the game's debug commands (e.g. `debug warp FarmHouse 1 1` warps you to the farmhouse). * Added basic context info to logs to simplify troubleshooting. * Added a `Mod.Dispose` method which can be overriden to clean up before exit. This method isn't guaranteed to be called on every exit. @@ -905,8 +906,8 @@ For players: For mod developers: * Added a content API which loads custom textures/maps/data from the mod's folder (`.xnb` or `.png` format) or game content. * `Console.Out` messages are now written to the log file. -* `Monitor.ExitGameImmediately` now aborts SMAPI initialisation and events more quickly. -* Fixed value-changed events being raised when the player loads a save due to values being initialised. +* `Monitor.ExitGameImmediately` now aborts SMAPI initialization and events more quickly. +* Fixed value-changed events being raised when the player loads a save due to values being initialized. ## 1.10 Released 24 April 2017 for Stardew Valley 1.2.26. @@ -922,7 +923,7 @@ For players: * Replaced `player_addmelee` with `player_addweapon` with support for non-melee weapons. For mod developers: -* Mods are now initialised after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method. +* Mods are now initialized after the `Initialize`/`LoadContent` phase, which means the `GameEvents.Initialize` and `GameEvents.LoadContent` events are deprecated. You can move any logic in those methods to your mod's `Entry` method. * Added `IsBetween` and string overloads to the `ISemanticVersion` methods. * Fixed mouse-changed event never updating prior mouse position. * Fixed `monitor.ExitGameImmediately` not working correctly. @@ -961,7 +962,7 @@ For mod developers: * The SMAPI log now has a simpler filename. * The SMAPI log now shows the OS caption (like "Windows 10") instead of its internal version when available. * The SMAPI log now always uses `\r\n` line endings to simplify crossplatform viewing. -* Fixed `SaveEvents.AfterLoad` being raised during the new-game intro before the player is initialised. +* Fixed `SaveEvents.AfterLoad` being raised during the new-game intro before the player is initialized. * Fixed SMAPI not recognising `Mod` instances that don't subclass `Mod` directly. * Several obsolete APIs have been removed (see [migration guides](https://stardewvalleywiki.com/Modding:Index#Migration_guides)), and all _notice_-level deprecations have been increased to _info_. @@ -1006,7 +1007,7 @@ For mod developers: * Added a mod registry which provides metadata about loaded mods. * The `Entry(…)` method is now deferred until all mods are loaded. * Fixed `SaveEvents.BeforeSave` and `.AfterSave` not triggering on days when the player shipped something. -* Fixed `PlayerEvents.LoadedGame` and `SaveEvents.AfterLoad` being fired before the world finishes initialising. +* Fixed `PlayerEvents.LoadedGame` and `SaveEvents.AfterLoad` being fired before the world finishes initializing. * Fixed some `LocationEvents`, `PlayerEvents`, and `TimeEvents` being fired during game startup. * Increased deprecation levels for `SObject`, `LogWriter` (not `Log`), and `Mod.Entry(ModHelper)` (not `Mod.Entry(IModHelper)`) to _pending removal_. Increased deprecation levels for `Mod.PerSaveConfigFolder`, `Mod.PerSaveConfigPath`, and `Version.VersionString` to _info_. diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 41400617..4d313a3b 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -106,7 +106,7 @@ namespace StardewModdingApi.Installer /// Run the install or uninstall script. /// The command line arguments. /// - /// Initialisation flow: + /// Initialization flow: /// 1. Collect information (mainly OS and install path) and validate it. /// 2. Ask the user whether to install or uninstall. /// @@ -218,7 +218,7 @@ namespace StardewModdingApi.Installer ****/ // get theme writers var lightBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.LightBackground); - var darkDarkgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.DarkBackground); + var darkBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.DarkBackground); // print question this.PrintPlain("Which text looks more readable?"); @@ -226,7 +226,7 @@ namespace StardewModdingApi.Installer Console.Write(" [1] "); lightBackgroundWriter.WriteLine("Dark text on light background", ConsoleLogLevel.Info); Console.Write(" [2] "); - darkDarkgroundWriter.WriteLine("Light text on dark background", ConsoleLogLevel.Info); + darkBackgroundWriter.WriteLine("Light text on dark background", ConsoleLogLevel.Info); Console.WriteLine(); // handle choice @@ -239,7 +239,7 @@ namespace StardewModdingApi.Installer break; case "2": scheme = MonitorColorScheme.DarkBackground; - this.ConsoleWriter = darkDarkgroundWriter; + this.ConsoleWriter = darkBackgroundWriter; break; default: throw new InvalidOperationException($"Unexpected action key '{choice}'."); @@ -646,7 +646,7 @@ namespace StardewModdingApi.Installer /// Delete a file or folder regardless of file permissions, and block until deletion completes. /// The file or folder to reset. - /// This method is mirred from FileUtilities.ForceDelete in the toolkit. + /// This method is mirrored from FileUtilities.ForceDelete in the toolkit. private void ForceDelete(FileSystemInfo entry) { // ignore if already deleted @@ -762,7 +762,7 @@ namespace StardewModdingApi.Installer continue; } - // normalise path + // normalize path if (platform == Platform.Windows) path = path.Replace("\"", ""); // in Windows, quotes are used to escape spaces and aren't part of the file path if (platform == Platform.Linux || platform == Platform.Mac) diff --git a/src/SMAPI.Installer/Program.cs b/src/SMAPI.Installer/Program.cs index 3c4d8593..b7fa45f5 100644 --- a/src/SMAPI.Installer/Program.cs +++ b/src/SMAPI.Installer/Program.cs @@ -36,7 +36,7 @@ namespace StardewModdingApi.Installer FileInfo zipFile = new FileInfo(Path.Combine(Program.InstallerPath, $"{(platform == PlatformID.Win32NT ? "windows" : "unix")}-install.dat")); if (!zipFile.Exists) { - Console.WriteLine($"Oops! Some of the installer files are missing; try redownloading the installer. (Missing file: {zipFile.FullName})"); + Console.WriteLine($"Oops! Some of the installer files are missing; try re-downloading the installer. (Missing file: {zipFile.FullName})"); Console.ReadLine(); return; } diff --git a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs index 40c2d986..db016bae 100644 --- a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs +++ b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs @@ -126,7 +126,7 @@ namespace StardewModdingAPI.Internal.ConsoleWriting case ConsoleColor.Black: case ConsoleColor.Blue: case ConsoleColor.DarkBlue: - case ConsoleColor.DarkMagenta: // Powershell + case ConsoleColor.DarkMagenta: // PowerShell case ConsoleColor.DarkRed: case ConsoleColor.Red: return true; diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/Netcode/NetFieldBase.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/Netcode/NetFieldBase.cs index 1684229a..140c6f59 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/Netcode/NetFieldBase.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/Netcode/NetFieldBase.cs @@ -2,7 +2,7 @@ namespace Netcode { /// A simplified version of Stardew Valley's Netcode.NetFieldBase for unit testing. - /// The type of the synchronised value. + /// The type of the synchronized value. /// The type of the current instance. public class NetFieldBase where TSelf : NetFieldBase { diff --git a/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs index 70c01418..a9b981bd 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/NetFieldAnalyzer.cs @@ -199,7 +199,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer /********* ** Private methods *********/ - /// Analyse a member access syntax node and add a diagnostic message if applicable. + /// Analyze a member access syntax node and add a diagnostic message if applicable. /// The analysis context. /// Returns whether any warnings were added. private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context) @@ -231,7 +231,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer }); } - /// Analyse an explicit cast or 'x as y' node and add a diagnostic message if applicable. + /// Analyze an explicit cast or 'x as y' node and add a diagnostic message if applicable. /// The analysis context. /// Returns whether any warnings were added. private void AnalyzeCast(SyntaxNodeAnalysisContext context) @@ -248,7 +248,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer }); } - /// Analyse a binary comparison syntax node and add a diagnostic message if applicable. + /// Analyze a binary comparison syntax node and add a diagnostic message if applicable. /// The analysis context. /// Returns whether any warnings were added. private void AnalyzeBinaryComparison(SyntaxNodeAnalysisContext context) @@ -288,7 +288,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer } /// Handle exceptions raised while analyzing a node. - /// The node being analysed. + /// The node being analyzed. /// The callback to invoke. private void HandleErrors(SyntaxNode node, Action action) { diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs index 6b935caa..d071f0c1 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ObsoleteFieldAnalyzer.cs @@ -67,7 +67,7 @@ namespace StardewModdingAPI.ModBuildConfig.Analyzer /********* ** Private methods *********/ - /// Analyse a syntax node and add a diagnostic message if it references an obsolete field. + /// Analyze a syntax node and add a diagnostic message if it references an obsolete field. /// The analysis context. private void AnalyzeObsoleteFields(SyntaxNodeAnalysisContext context) { diff --git a/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs b/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs index e67a18c1..a852f133 100644 --- a/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs +++ b/src/SMAPI.ModBuildConfig/Framework/ModFileManager.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization; +using StardewModdingAPI.Toolkit.Serialization.Models; using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.ModBuildConfig.Framework diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs index 263e126c..6cb2b624 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/AddCommand.cs @@ -15,7 +15,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player /// Provides methods for searching and constructing items. private readonly ItemRepository Items = new ItemRepository(); - /// The type names recognised by this command. + /// The type names recognized by this command. private readonly string[] ValidTypes = Enum.GetNames(typeof(ItemType)).Concat(new[] { "Name" }).ToArray(); diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs index 5b52e9a2..4232ce16 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/ListItemsCommand.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using StardewModdingAPI.Mods.ConsoleCommands.Framework.ItemData; @@ -58,7 +58,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player /// The search string to find. private IEnumerable GetItems(string[] searchWords) { - // normalise search term + // normalize search term searchWords = searchWords?.Where(word => !string.IsNullOrWhiteSpace(word)).ToArray(); if (searchWords?.Any() == false) searchWords = null; diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetTimeCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetTimeCommand.cs index a6075013..9eae6741 100644 --- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetTimeCommand.cs +++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/SetTimeCommand.cs @@ -60,7 +60,7 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World { for (int i = 0; i > intervals; i--) { - Game1.timeOfDay = FromTimeSpan(ToTimeSpan(Game1.timeOfDay).Subtract(TimeSpan.FromMinutes(20))); // offset 20 mins so game updates to next interval + Game1.timeOfDay = FromTimeSpan(ToTimeSpan(Game1.timeOfDay).Subtract(TimeSpan.FromMinutes(20))); // offset 20 minutes so game updates to next interval Game1.performTenMinuteClockUpdate(); } } diff --git a/src/SMAPI.Tests/Core/ModResolverTests.cs b/src/SMAPI.Tests/Core/ModResolverTests.cs index ee1c0b99..c1aa0212 100644 --- a/src/SMAPI.Tests/Core/ModResolverTests.cs +++ b/src/SMAPI.Tests/Core/ModResolverTests.cs @@ -9,7 +9,7 @@ using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.ModLoading; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.ModData; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization.Models; namespace StardewModdingAPI.Tests.Core { @@ -55,7 +55,7 @@ namespace StardewModdingAPI.Tests.Core Assert.IsNotNull(mod.Error, "The mod metadata did not have an error message set."); } - [Test(Description = "Assert that the resolver correctly reads manifest data from a randomised file.")] + [Test(Description = "Assert that the resolver correctly reads manifest data from a randomized file.")] public void ReadBasicManifest_CanReadFile() { // create manifest data @@ -468,7 +468,7 @@ namespace StardewModdingAPI.Tests.Core return Path.Combine(Path.GetTempPath(), "smapi-unit-tests", Guid.NewGuid().ToString("N")); } - /// Get a randomised basic manifest. + /// Get a randomized basic manifest. /// The value, or null for a generated value. /// The value, or null for a generated value. /// The value, or null for a generated value. @@ -492,14 +492,14 @@ namespace StardewModdingAPI.Tests.Core }; } - /// Get a randomised basic manifest. + /// Get a randomized basic manifest. /// The mod's name and unique ID. private Mock GetMetadata(string uniqueID) { return this.GetMetadata(this.GetManifest(uniqueID, "1.0")); } - /// Get a randomised basic manifest. + /// Get a randomized basic manifest. /// The mod's name and unique ID. /// The dependencies this mod requires. /// Whether the code being tested is allowed to change the mod status. @@ -509,7 +509,7 @@ namespace StardewModdingAPI.Tests.Core return this.GetMetadata(manifest, allowStatusChange); } - /// Get a randomised basic manifest. + /// Get a randomized basic manifest. /// The mod manifest. /// Whether the code being tested is allowed to change the mod status. private Mock GetMetadata(IManifest manifest, bool allowStatusChange = false) diff --git a/src/SMAPI.Tests/Core/TranslationTests.cs b/src/SMAPI.Tests/Core/TranslationTests.cs index 63404a41..eea301ae 100644 --- a/src/SMAPI.Tests/Core/TranslationTests.cs +++ b/src/SMAPI.Tests/Core/TranslationTests.cs @@ -245,7 +245,7 @@ namespace StardewModdingAPI.Tests.Core [TestCase("{{value}}", "value")] [TestCase("{{VaLuE}}", "vAlUe")] [TestCase("{{VaLuE }}", " vAlUe")] - public void Translation_Tokens_KeysAreNormalised(string text, string key) + public void Translation_Tokens_KeysAreNormalized(string text, string key) { // arrange string value = Guid.NewGuid().ToString("N"); diff --git a/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs b/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs index 229b9a14..3dc65ed5 100644 --- a/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs +++ b/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs @@ -25,7 +25,7 @@ namespace StardewModdingAPI.Tests.Toolkit return string.Join("|", PathUtilities.GetSegments(path)); } - [Test(Description = "Assert that NormalisePathSeparators returns the expected values.")] + [Test(Description = "Assert that NormalizePathSeparators returns the expected values.")] #if SMAPI_FOR_WINDOWS [TestCase("", ExpectedResult = "")] [TestCase("/", ExpectedResult = "")] @@ -47,9 +47,9 @@ namespace StardewModdingAPI.Tests.Toolkit [TestCase("C:/boop", ExpectedResult = "C:/boop")] [TestCase(@"C:\usr\bin//.././boop.exe", ExpectedResult = "C:/usr/bin/.././boop.exe")] #endif - public string NormalisePathSeparators(string path) + public string NormalizePathSeparators(string path) { - return PathUtilities.NormalisePathSeparators(path); + return PathUtilities.NormalizePathSeparators(path); } [Test(Description = "Assert that GetRelativePath returns the expected values.")] diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs index 2e7719eb..8f64a5fb 100644 --- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs +++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs @@ -243,19 +243,19 @@ namespace StardewModdingAPI.Tests.Utilities } /**** - ** Serialisable + ** Serializable ****/ [Test(Description = "Assert that SemanticVersion can be round-tripped through JSON with no special configuration.")] [TestCase("1.0")] - public void Serialisable(string versionStr) + public void Serializable(string versionStr) { // act string json = JsonConvert.SerializeObject(new SemanticVersion(versionStr)); SemanticVersion after = JsonConvert.DeserializeObject(json); // assert - Assert.IsNotNull(after, "The semantic version after deserialisation is unexpectedly null."); - Assert.AreEqual(versionStr, after.ToString(), "The semantic version after deserialisation doesn't match the input version."); + Assert.IsNotNull(after, "The semantic version after deserialization is unexpectedly null."); + Assert.AreEqual(versionStr, after.ToString(), "The semantic version after deserialization doesn't match the input version."); } /**** diff --git a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs index 4a61f9ae..4ec87d7c 100644 --- a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs +++ b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs @@ -24,7 +24,7 @@ namespace StardewModdingAPI /********* ** Accessors *********/ - /// Whether this is a pre-release version. + /// Whether this is a prerelease version. bool IsPrerelease(); /// Get whether this version is older than the specified version. diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs index 989c18b0..bd5f71a9 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs @@ -48,7 +48,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi [JsonConverter(typeof(StringEnumConverter))] public WikiCompatibilityStatus? CompatibilityStatus { get; set; } - /// The human-readable summary of the compatibility status or workaround, without HTML formatitng. + /// The human-readable summary of the compatibility status or workaround, without HTML formatting. public string CompatibilitySummary { get; set; } /// The game or SMAPI version which broke this mod, if applicable. @@ -62,7 +62,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi [JsonConverter(typeof(StringEnumConverter))] public WikiCompatibilityStatus? BetaCompatibilityStatus { get; set; } - /// The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatitng. + /// The human-readable summary of the compatibility status or workaround for the Stardew Valley beta (if any), without HTML formatting. public string BetaCompatibilitySummary { get; set; } /// The beta game or SMAPI version which broke this mod, if applicable. diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs index e352e1cc..a2eaad16 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs @@ -21,7 +21,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Construct an empty instance. public ModSearchModel() { - // needed for JSON deserialising + // needed for JSON deserializing } /// Construct an instance. diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs index bca47647..886cd5a1 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs @@ -19,7 +19,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Construct an empty instance. public ModSearchEntryModel() { - // needed for JSON deserialising + // needed for JSON deserializing } /// Construct an instance. diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs index 7c3df384..80c8f62b 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; using Newtonsoft.Json; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi { diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs index 60c7a682..212c70ef 100644 --- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs +++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs @@ -29,7 +29,7 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning IEnumerable paths = this .GetCustomInstallPaths(platform) .Concat(this.GetDefaultInstallPaths(platform)) - .Select(PathUtilities.NormalisePathSeparators) + .Select(PathUtilities.NormalizePathSeparators) .Distinct(StringComparer.InvariantCultureIgnoreCase); // yield valid folders diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs index 18039762..dd0bd07b 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs @@ -112,8 +112,8 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /********* ** Private methods *********/ - /// The method invoked after JSON deserialisation. - /// The deserialisation context. + /// The method invoked after JSON deserialization. + /// The deserialization context. [OnDeserialized] private void OnDeserialized(StreamingContext context) { diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs index 794ad2e4..f01ada7c 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs @@ -68,7 +68,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData } /// Get a semantic local version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) { return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion) @@ -77,10 +77,10 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData } /// Get a semantic remote version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public string GetRemoteVersionForUpdateChecks(string version) { - // normalise version if possible + // normalize version if possible if (SemanticVersion.TryParse(version, out ISemanticVersion parsed)) version = parsed.ToString(); diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs index 237f2c66..9e22990d 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs @@ -32,14 +32,14 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData ** Public methods *********/ /// Get a semantic local version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) { return this.DataRecord.GetLocalVersionForUpdateChecks(version); } /// Get a semantic remote version for update checks. - /// The remote version to normalise. + /// The remote version to normalize. public ISemanticVersion GetRemoteVersionForUpdateChecks(ISemanticVersion version) { if (version == null) diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs index d61c427f..e67616d0 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModWarning.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData BrokenCodeLoaded = 1, /// The mod affects the save serializer in a way that may make saves unloadable without the mod. - ChangesSaveSerialiser = 2, + ChangesSaveSerializer = 2, /// The mod patches the game in a way that may impact stability. PatchesGame = 4, @@ -21,7 +21,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// The mod uses the dynamic keyword which won't work on Linux/Mac. UsesDynamic = 8, - /// The mod references specialised 'unvalided update tick' events which may impact stability. + /// The mod references specialized 'unvalidated update tick' events which may impact stability. UsesUnvalidatedUpdateTick = 16, /// The mod has no update keys set. diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs index 4ce17c66..d0df09a1 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModFolder.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization.Models; using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Toolkit.Framework.ModScanning diff --git a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs index 54cb2b8b..f11cc1a7 100644 --- a/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs +++ b/src/SMAPI.Toolkit/Framework/ModScanning/ModScanner.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization; +using StardewModdingAPI.Toolkit.Serialization.Models; namespace StardewModdingAPI.Toolkit.Framework.ModScanning { @@ -118,7 +118,7 @@ namespace StardewModdingAPI.Toolkit.Framework.ModScanning } } - // normalise display fields + // normalize display fields if (manifest != null) { manifest.Name = this.StripNewlines(manifest.Name); diff --git a/src/SMAPI.Toolkit/ModToolkit.cs b/src/SMAPI.Toolkit/ModToolkit.cs index 4b026b7a..08fe0fed 100644 --- a/src/SMAPI.Toolkit/ModToolkit.cs +++ b/src/SMAPI.Toolkit/ModToolkit.cs @@ -8,7 +8,7 @@ using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; using StardewModdingAPI.Toolkit.Framework.GameScanning; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Framework.ModScanning; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; namespace StardewModdingAPI.Toolkit { diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs index 78b4c007..6d5d65ac 100644 --- a/src/SMAPI.Toolkit/SemanticVersion.cs +++ b/src/SMAPI.Toolkit/SemanticVersion.cs @@ -56,7 +56,7 @@ namespace StardewModdingAPI.Toolkit this.MajorVersion = major; this.MinorVersion = minor; this.PatchVersion = patch; - this.PrereleaseTag = this.GetNormalisedTag(prereleaseTag); + this.PrereleaseTag = this.GetNormalizedTag(prereleaseTag); this.AssertValid(); } @@ -89,16 +89,16 @@ namespace StardewModdingAPI.Toolkit if (!match.Success) throw new FormatException($"The input '{version}' isn't a valid semantic version."); - // initialise + // initialize this.MajorVersion = int.Parse(match.Groups["major"].Value); this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0; this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0; - this.PrereleaseTag = match.Groups["prerelease"].Success ? this.GetNormalisedTag(match.Groups["prerelease"].Value) : null; + this.PrereleaseTag = match.Groups["prerelease"].Success ? this.GetNormalizedTag(match.Groups["prerelease"].Value) : null; this.AssertValid(); } - /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. + /// Get an integer indicating whether this version precedes (less than 0), supersedes (more than 0), or is equivalent to (0) the specified version. /// The version to compare with this instance. /// The value is null. public int CompareTo(ISemanticVersion other) @@ -116,7 +116,7 @@ namespace StardewModdingAPI.Toolkit return other != null && this.CompareTo(other) == 0; } - /// Whether this is a pre-release version. + /// Whether this is a prerelease version. public bool IsPrerelease() { return !string.IsNullOrWhiteSpace(this.PrereleaseTag); @@ -206,15 +206,15 @@ namespace StardewModdingAPI.Toolkit /********* ** Private methods *********/ - /// Get a normalised build tag. - /// The tag to normalise. - private string GetNormalisedTag(string tag) + /// Get a normalized build tag. + /// The tag to normalize. + private string GetNormalizedTag(string tag) { tag = tag?.Trim(); return !string.IsNullOrWhiteSpace(tag) ? tag : null; } - /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. + /// Get an integer indicating whether this version precedes (less than 0), supersedes (more than 0), or is equivalent to (0) the specified version. /// The major version to compare with this instance. /// The minor version to compare with this instance. /// The patch version to compare with this instance. @@ -235,7 +235,7 @@ namespace StardewModdingAPI.Toolkit if (this.PrereleaseTag == otherTag) return same; - // stable supercedes pre-release + // stable supersedes prerelease bool curIsStable = string.IsNullOrWhiteSpace(this.PrereleaseTag); bool otherIsStable = string.IsNullOrWhiteSpace(otherTag); if (curIsStable) @@ -243,12 +243,12 @@ namespace StardewModdingAPI.Toolkit if (otherIsStable) return curOlder; - // compare two pre-release tag values + // compare two prerelease tag values string[] curParts = this.PrereleaseTag.Split('.', '-'); string[] otherParts = otherTag.Split('.', '-'); for (int i = 0; i < curParts.Length; i++) { - // longer prerelease tag supercedes if otherwise equal + // longer prerelease tag supersedes if otherwise equal if (otherParts.Length <= i) return curNewer; diff --git a/src/SMAPI.Toolkit/Serialisation/Converters/ManifestContentPackForConverter.cs b/src/SMAPI.Toolkit/Serialisation/Converters/ManifestContentPackForConverter.cs deleted file mode 100644 index 232c22a7..00000000 --- a/src/SMAPI.Toolkit/Serialisation/Converters/ManifestContentPackForConverter.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using Newtonsoft.Json; -using StardewModdingAPI.Toolkit.Serialisation.Models; - -namespace StardewModdingAPI.Toolkit.Serialisation.Converters -{ - /// Handles deserialisation of arrays. - public class ManifestContentPackForConverter : JsonConverter - { - /********* - ** Accessors - *********/ - /// Whether this converter can write JSON. - public override bool CanWrite => false; - - - /********* - ** Public methods - *********/ - /// Get whether this instance can convert the specified object type. - /// The object type. - public override bool CanConvert(Type objectType) - { - return objectType == typeof(ManifestContentPackFor[]); - } - - - /********* - ** Protected methods - *********/ - /// Read the JSON representation of the object. - /// The JSON reader. - /// The object type. - /// The object being read. - /// The calling serializer. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - return serializer.Deserialize(reader); - } - - /// Writes the JSON representation of the object. - /// The JSON writer. - /// The value. - /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new InvalidOperationException("This converter does not write JSON."); - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/Converters/ManifestDependencyArrayConverter.cs b/src/SMAPI.Toolkit/Serialisation/Converters/ManifestDependencyArrayConverter.cs deleted file mode 100644 index 0a304ee3..00000000 --- a/src/SMAPI.Toolkit/Serialisation/Converters/ManifestDependencyArrayConverter.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using StardewModdingAPI.Toolkit.Serialisation.Models; - -namespace StardewModdingAPI.Toolkit.Serialisation.Converters -{ - /// Handles deserialisation of arrays. - internal class ManifestDependencyArrayConverter : JsonConverter - { - /********* - ** Accessors - *********/ - /// Whether this converter can write JSON. - public override bool CanWrite => false; - - - /********* - ** Public methods - *********/ - /// Get whether this instance can convert the specified object type. - /// The object type. - public override bool CanConvert(Type objectType) - { - return objectType == typeof(ManifestDependency[]); - } - - - /********* - ** Protected methods - *********/ - /// Read the JSON representation of the object. - /// The JSON reader. - /// The object type. - /// The object being read. - /// The calling serializer. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - List result = new List(); - foreach (JObject obj in JArray.Load(reader).Children()) - { - string uniqueID = obj.ValueIgnoreCase(nameof(ManifestDependency.UniqueID)); - string minVersion = obj.ValueIgnoreCase(nameof(ManifestDependency.MinimumVersion)); - bool required = obj.ValueIgnoreCase(nameof(ManifestDependency.IsRequired)) ?? true; - result.Add(new ManifestDependency(uniqueID, minVersion, required)); - } - return result.ToArray(); - } - - /// Writes the JSON representation of the object. - /// The JSON writer. - /// The value. - /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new InvalidOperationException("This converter does not write JSON."); - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs b/src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs deleted file mode 100644 index c50de4db..00000000 --- a/src/SMAPI.Toolkit/Serialisation/Converters/SemanticVersionConverter.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace StardewModdingAPI.Toolkit.Serialisation.Converters -{ - /// Handles deserialisation of . - internal class SemanticVersionConverter : JsonConverter - { - /********* - ** Accessors - *********/ - /// Get whether this converter can read JSON. - public override bool CanRead => true; - - /// Get whether this converter can write JSON. - public override bool CanWrite => true; - - - /********* - ** Public methods - *********/ - /// Get whether this instance can convert the specified object type. - /// The object type. - public override bool CanConvert(Type objectType) - { - return typeof(ISemanticVersion).IsAssignableFrom(objectType); - } - - /// Reads the JSON representation of the object. - /// The JSON reader. - /// The object type. - /// The object being read. - /// The calling serializer. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - string path = reader.Path; - switch (reader.TokenType) - { - case JsonToken.StartObject: - return this.ReadObject(JObject.Load(reader)); - case JsonToken.String: - return this.ReadString(JToken.Load(reader).Value(), path); - default: - throw new SParseException($"Can't parse {nameof(ISemanticVersion)} from {reader.TokenType} node (path: {reader.Path})."); - } - } - - /// Writes the JSON representation of the object. - /// The JSON writer. - /// The value. - /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - writer.WriteValue(value?.ToString()); - } - - - /********* - ** Private methods - *********/ - /// Read a JSON object. - /// The JSON object to read. - private ISemanticVersion ReadObject(JObject obj) - { - int major = obj.ValueIgnoreCase(nameof(ISemanticVersion.MajorVersion)); - int minor = obj.ValueIgnoreCase(nameof(ISemanticVersion.MinorVersion)); - int patch = obj.ValueIgnoreCase(nameof(ISemanticVersion.PatchVersion)); - string prereleaseTag = obj.ValueIgnoreCase(nameof(ISemanticVersion.PrereleaseTag)); - - return new SemanticVersion(major, minor, patch, prereleaseTag); - } - - /// Read a JSON string. - /// The JSON string value. - /// The path to the current JSON node. - private ISemanticVersion ReadString(string str, string path) - { - if (string.IsNullOrWhiteSpace(str)) - return null; - if (!SemanticVersion.TryParse(str, out ISemanticVersion version)) - throw new SParseException($"Can't parse semantic version from invalid value '{str}', should be formatted like 1.2, 1.2.30, or 1.2.30-beta (path: {path})."); - return version; - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/Converters/SimpleReadOnlyConverter.cs b/src/SMAPI.Toolkit/Serialisation/Converters/SimpleReadOnlyConverter.cs deleted file mode 100644 index 5e0b0f4a..00000000 --- a/src/SMAPI.Toolkit/Serialisation/Converters/SimpleReadOnlyConverter.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace StardewModdingAPI.Toolkit.Serialisation.Converters -{ - /// The base implementation for simplified converters which deserialise without overriding serialisation. - /// The type to deserialise. - internal abstract class SimpleReadOnlyConverter : JsonConverter - { - /********* - ** Accessors - *********/ - /// Whether this converter can write JSON. - public override bool CanWrite => false; - - - /********* - ** Public methods - *********/ - /// Get whether this instance can convert the specified object type. - /// The object type. - public override bool CanConvert(Type objectType) - { - return objectType == typeof(T); - } - - /// Writes the JSON representation of the object. - /// The JSON writer. - /// The value. - /// The calling serializer. - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new InvalidOperationException("This converter does not write JSON."); - } - - /// Reads the JSON representation of the object. - /// The JSON reader. - /// The object type. - /// The object being read. - /// The calling serializer. - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - string path = reader.Path; - switch (reader.TokenType) - { - case JsonToken.StartObject: - return this.ReadObject(JObject.Load(reader), path); - case JsonToken.String: - return this.ReadString(JToken.Load(reader).Value(), path); - default: - throw new SParseException($"Can't parse {typeof(T).Name} from {reader.TokenType} node (path: {reader.Path})."); - } - } - - - /********* - ** Protected methods - *********/ - /// Read a JSON object. - /// The JSON object to read. - /// The path to the current JSON node. - protected virtual T ReadObject(JObject obj, string path) - { - throw new SParseException($"Can't parse {typeof(T).Name} from object node (path: {path})."); - } - - /// Read a JSON string. - /// The JSON string value. - /// The path to the current JSON node. - protected virtual T ReadString(string str, string path) - { - throw new SParseException($"Can't parse {typeof(T).Name} from string node (path: {path})."); - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/InternalExtensions.cs b/src/SMAPI.Toolkit/Serialisation/InternalExtensions.cs deleted file mode 100644 index 12b2c933..00000000 --- a/src/SMAPI.Toolkit/Serialisation/InternalExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using Newtonsoft.Json.Linq; - -namespace StardewModdingAPI.Toolkit.Serialisation -{ - /// Provides extension methods for parsing JSON. - public static class JsonExtensions - { - /// Get a JSON field value from a case-insensitive field name. This will check for an exact match first, then search without case sensitivity. - /// The value type. - /// The JSON object to search. - /// The field name. - public static T ValueIgnoreCase(this JObject obj, string fieldName) - { - JToken token = obj.GetValue(fieldName, StringComparison.InvariantCultureIgnoreCase); - return token != null - ? token.Value() - : default(T); - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/JsonHelper.cs b/src/SMAPI.Toolkit/Serialisation/JsonHelper.cs deleted file mode 100644 index cf2ce0d1..00000000 --- a/src/SMAPI.Toolkit/Serialisation/JsonHelper.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using StardewModdingAPI.Toolkit.Serialisation.Converters; - -namespace StardewModdingAPI.Toolkit.Serialisation -{ - /// Encapsulates SMAPI's JSON file parsing. - public class JsonHelper - { - /********* - ** Accessors - *********/ - /// The JSON settings to use when serialising and deserialising files. - public JsonSerializerSettings JsonSettings { get; } = new JsonSerializerSettings - { - Formatting = Formatting.Indented, - ObjectCreationHandling = ObjectCreationHandling.Replace, // avoid issue where default ICollection values are duplicated each time the config is loaded - Converters = new List - { - new SemanticVersionConverter(), - new StringEnumConverter() - } - }; - - - /********* - ** Public methods - *********/ - /// Read a JSON file. - /// The model type. - /// The absolete file path. - /// The parsed content model. - /// Returns false if the file doesn't exist, else true. - /// The given is empty or invalid. - /// The file contains invalid JSON. - public bool ReadJsonFileIfExists(string fullPath, out TModel result) - { - // validate - if (string.IsNullOrWhiteSpace(fullPath)) - throw new ArgumentException("The file path is empty or invalid.", nameof(fullPath)); - - // read file - string json; - try - { - json = File.ReadAllText(fullPath); - } - catch (Exception ex) when (ex is DirectoryNotFoundException || ex is FileNotFoundException) - { - result = default(TModel); - return false; - } - - // deserialise model - try - { - result = this.Deserialise(json); - return true; - } - catch (Exception ex) - { - string error = $"Can't parse JSON file at {fullPath}."; - - if (ex is JsonReaderException) - { - error += " This doesn't seem to be valid JSON."; - if (json.Contains("“") || json.Contains("”")) - error += " Found curly quotes in the text; note that only straight quotes are allowed in JSON."; - } - error += $"\nTechnical details: {ex.Message}"; - throw new JsonReaderException(error); - } - } - - /// Save to a JSON file. - /// The model type. - /// The absolete file path. - /// The model to save. - /// The given path is empty or invalid. - public void WriteJsonFile(string fullPath, TModel model) - where TModel : class - { - // validate - if (string.IsNullOrWhiteSpace(fullPath)) - throw new ArgumentException("The file path is empty or invalid.", nameof(fullPath)); - - // create directory if needed - string dir = Path.GetDirectoryName(fullPath); - if (dir == null) - throw new ArgumentException("The file path is invalid.", nameof(fullPath)); - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - // write file - string json = this.Serialise(model); - File.WriteAllText(fullPath, json); - } - - /// Deserialize JSON text if possible. - /// The model type. - /// The raw JSON text. - public TModel Deserialise(string json) - { - try - { - return JsonConvert.DeserializeObject(json, this.JsonSettings); - } - catch (JsonReaderException) - { - // try replacing curly quotes - if (json.Contains("“") || json.Contains("”")) - { - try - { - return JsonConvert.DeserializeObject(json.Replace('“', '"').Replace('”', '"'), this.JsonSettings); - } - catch { /* rethrow original error */ } - } - - throw; - } - } - - /// Serialize a model to JSON text. - /// The model type. - /// The model to serialise. - /// The formatting to apply. - public string Serialise(TModel model, Formatting formatting = Formatting.Indented) - { - return JsonConvert.SerializeObject(model, formatting, this.JsonSettings); - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/Models/Manifest.cs b/src/SMAPI.Toolkit/Serialisation/Models/Manifest.cs deleted file mode 100644 index 6cb9496b..00000000 --- a/src/SMAPI.Toolkit/Serialisation/Models/Manifest.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; -using StardewModdingAPI.Toolkit.Serialisation.Converters; - -namespace StardewModdingAPI.Toolkit.Serialisation.Models -{ - /// A manifest which describes a mod for SMAPI. - public class Manifest : IManifest - { - /********* - ** Accessors - *********/ - /// The mod name. - public string Name { get; set; } - - /// A brief description of the mod. - public string Description { get; set; } - - /// The mod author's name. - public string Author { get; set; } - - /// The mod version. - public ISemanticVersion Version { get; set; } - - /// The minimum SMAPI version required by this mod, if any. - public ISemanticVersion MinimumApiVersion { get; set; } - - /// The name of the DLL in the directory that has the Entry method. Mutually exclusive with . - public string EntryDll { get; set; } - - /// The mod which will read this as a content pack. Mutually exclusive with . - [JsonConverter(typeof(ManifestContentPackForConverter))] - public IManifestContentPackFor ContentPackFor { get; set; } - - /// The other mods that must be loaded before this mod. - [JsonConverter(typeof(ManifestDependencyArrayConverter))] - public IManifestDependency[] Dependencies { get; set; } - - /// The namespaced mod IDs to query for updates (like Nexus:541). - public string[] UpdateKeys { get; set; } - - /// The unique mod ID. - public string UniqueID { get; set; } - - /// Any manifest fields which didn't match a valid field. - [JsonExtensionData] - public IDictionary ExtraFields { get; set; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - public Manifest() { } - - /// Construct an instance for a transitional content pack. - /// The unique mod ID. - /// The mod name. - /// The mod author's name. - /// A brief description of the mod. - /// The mod version. - /// The modID which will read this as a content pack. - public Manifest(string uniqueID, string name, string author, string description, ISemanticVersion version, string contentPackFor = null) - { - this.Name = name; - this.Author = author; - this.Description = description; - this.Version = version; - this.UniqueID = uniqueID; - this.UpdateKeys = new string[0]; - this.ContentPackFor = new ManifestContentPackFor { UniqueID = contentPackFor }; - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs b/src/SMAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs deleted file mode 100644 index d0e42216..00000000 --- a/src/SMAPI.Toolkit/Serialisation/Models/ManifestContentPackFor.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Serialisation.Models -{ - /// Indicates which mod can read the content pack represented by the containing manifest. - public class ManifestContentPackFor : IManifestContentPackFor - { - /********* - ** Accessors - *********/ - /// The unique ID of the mod which can read this content pack. - public string UniqueID { get; set; } - - /// The minimum required version (if any). - public ISemanticVersion MinimumVersion { get; set; } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/Models/ManifestDependency.cs b/src/SMAPI.Toolkit/Serialisation/Models/ManifestDependency.cs deleted file mode 100644 index 8db58d5d..00000000 --- a/src/SMAPI.Toolkit/Serialisation/Models/ManifestDependency.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace StardewModdingAPI.Toolkit.Serialisation.Models -{ - /// A mod dependency listed in a mod manifest. - public class ManifestDependency : IManifestDependency - { - /********* - ** Accessors - *********/ - /// The unique mod ID to require. - public string UniqueID { get; set; } - - /// The minimum required version (if any). - public ISemanticVersion MinimumVersion { get; set; } - - /// Whether the dependency must be installed to use the mod. - public bool IsRequired { get; set; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The unique mod ID to require. - /// The minimum required version (if any). - /// Whether the dependency must be installed to use the mod. - public ManifestDependency(string uniqueID, string minimumVersion, bool required = true) - { - this.UniqueID = uniqueID; - this.MinimumVersion = !string.IsNullOrWhiteSpace(minimumVersion) - ? new SemanticVersion(minimumVersion) - : null; - this.IsRequired = required; - } - } -} diff --git a/src/SMAPI.Toolkit/Serialisation/SParseException.cs b/src/SMAPI.Toolkit/Serialisation/SParseException.cs deleted file mode 100644 index 61a7b305..00000000 --- a/src/SMAPI.Toolkit/Serialisation/SParseException.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace StardewModdingAPI.Toolkit.Serialisation -{ - /// A format exception which provides a user-facing error message. - internal class SParseException : FormatException - { - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The error message. - /// The underlying exception, if any. - public SParseException(string message, Exception ex = null) - : base(message, ex) { } - } -} diff --git a/src/SMAPI.Toolkit/Serialization/Converters/ManifestContentPackForConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/ManifestContentPackForConverter.cs new file mode 100644 index 00000000..5cabe9d8 --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/Converters/ManifestContentPackForConverter.cs @@ -0,0 +1,50 @@ +using System; +using Newtonsoft.Json; +using StardewModdingAPI.Toolkit.Serialization.Models; + +namespace StardewModdingAPI.Toolkit.Serialization.Converters +{ + /// Handles deserialization of arrays. + public class ManifestContentPackForConverter : JsonConverter + { + /********* + ** Accessors + *********/ + /// Whether this converter can write JSON. + public override bool CanWrite => false; + + + /********* + ** Public methods + *********/ + /// Get whether this instance can convert the specified object type. + /// The object type. + public override bool CanConvert(Type objectType) + { + return objectType == typeof(ManifestContentPackFor[]); + } + + + /********* + ** Protected methods + *********/ + /// Read the JSON representation of the object. + /// The JSON reader. + /// The object type. + /// The object being read. + /// The calling serializer. + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return serializer.Deserialize(reader); + } + + /// Writes the JSON representation of the object. + /// The JSON writer. + /// The value. + /// The calling serializer. + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new InvalidOperationException("This converter does not write JSON."); + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/Converters/ManifestDependencyArrayConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/ManifestDependencyArrayConverter.cs new file mode 100644 index 00000000..7b88d6b7 --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/Converters/ManifestDependencyArrayConverter.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using StardewModdingAPI.Toolkit.Serialization.Models; + +namespace StardewModdingAPI.Toolkit.Serialization.Converters +{ + /// Handles deserialization of arrays. + internal class ManifestDependencyArrayConverter : JsonConverter + { + /********* + ** Accessors + *********/ + /// Whether this converter can write JSON. + public override bool CanWrite => false; + + + /********* + ** Public methods + *********/ + /// Get whether this instance can convert the specified object type. + /// The object type. + public override bool CanConvert(Type objectType) + { + return objectType == typeof(ManifestDependency[]); + } + + + /********* + ** Protected methods + *********/ + /// Read the JSON representation of the object. + /// The JSON reader. + /// The object type. + /// The object being read. + /// The calling serializer. + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + List result = new List(); + foreach (JObject obj in JArray.Load(reader).Children()) + { + string uniqueID = obj.ValueIgnoreCase(nameof(ManifestDependency.UniqueID)); + string minVersion = obj.ValueIgnoreCase(nameof(ManifestDependency.MinimumVersion)); + bool required = obj.ValueIgnoreCase(nameof(ManifestDependency.IsRequired)) ?? true; + result.Add(new ManifestDependency(uniqueID, minVersion, required)); + } + return result.ToArray(); + } + + /// Writes the JSON representation of the object. + /// The JSON writer. + /// The value. + /// The calling serializer. + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new InvalidOperationException("This converter does not write JSON."); + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs new file mode 100644 index 00000000..ece4a72e --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/Converters/SemanticVersionConverter.cs @@ -0,0 +1,86 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace StardewModdingAPI.Toolkit.Serialization.Converters +{ + /// Handles deserialization of . + internal class SemanticVersionConverter : JsonConverter + { + /********* + ** Accessors + *********/ + /// Get whether this converter can read JSON. + public override bool CanRead => true; + + /// Get whether this converter can write JSON. + public override bool CanWrite => true; + + + /********* + ** Public methods + *********/ + /// Get whether this instance can convert the specified object type. + /// The object type. + public override bool CanConvert(Type objectType) + { + return typeof(ISemanticVersion).IsAssignableFrom(objectType); + } + + /// Reads the JSON representation of the object. + /// The JSON reader. + /// The object type. + /// The object being read. + /// The calling serializer. + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + string path = reader.Path; + switch (reader.TokenType) + { + case JsonToken.StartObject: + return this.ReadObject(JObject.Load(reader)); + case JsonToken.String: + return this.ReadString(JToken.Load(reader).Value(), path); + default: + throw new SParseException($"Can't parse {nameof(ISemanticVersion)} from {reader.TokenType} node (path: {reader.Path})."); + } + } + + /// Writes the JSON representation of the object. + /// The JSON writer. + /// The value. + /// The calling serializer. + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(value?.ToString()); + } + + + /********* + ** Private methods + *********/ + /// Read a JSON object. + /// The JSON object to read. + private ISemanticVersion ReadObject(JObject obj) + { + int major = obj.ValueIgnoreCase(nameof(ISemanticVersion.MajorVersion)); + int minor = obj.ValueIgnoreCase(nameof(ISemanticVersion.MinorVersion)); + int patch = obj.ValueIgnoreCase(nameof(ISemanticVersion.PatchVersion)); + string prereleaseTag = obj.ValueIgnoreCase(nameof(ISemanticVersion.PrereleaseTag)); + + return new SemanticVersion(major, minor, patch, prereleaseTag); + } + + /// Read a JSON string. + /// The JSON string value. + /// The path to the current JSON node. + private ISemanticVersion ReadString(string str, string path) + { + if (string.IsNullOrWhiteSpace(str)) + return null; + if (!SemanticVersion.TryParse(str, out ISemanticVersion version)) + throw new SParseException($"Can't parse semantic version from invalid value '{str}', should be formatted like 1.2, 1.2.30, or 1.2.30-beta (path: {path})."); + return version; + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs new file mode 100644 index 00000000..549f0c18 --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs @@ -0,0 +1,76 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace StardewModdingAPI.Toolkit.Serialization.Converters +{ + /// The base implementation for simplified converters which deserialize without overriding serialization. + /// The type to deserialize. + internal abstract class SimpleReadOnlyConverter : JsonConverter + { + /********* + ** Accessors + *********/ + /// Whether this converter can write JSON. + public override bool CanWrite => false; + + + /********* + ** Public methods + *********/ + /// Get whether this instance can convert the specified object type. + /// The object type. + public override bool CanConvert(Type objectType) + { + return objectType == typeof(T); + } + + /// Writes the JSON representation of the object. + /// The JSON writer. + /// The value. + /// The calling serializer. + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new InvalidOperationException("This converter does not write JSON."); + } + + /// Reads the JSON representation of the object. + /// The JSON reader. + /// The object type. + /// The object being read. + /// The calling serializer. + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + string path = reader.Path; + switch (reader.TokenType) + { + case JsonToken.StartObject: + return this.ReadObject(JObject.Load(reader), path); + case JsonToken.String: + return this.ReadString(JToken.Load(reader).Value(), path); + default: + throw new SParseException($"Can't parse {typeof(T).Name} from {reader.TokenType} node (path: {reader.Path})."); + } + } + + + /********* + ** Protected methods + *********/ + /// Read a JSON object. + /// The JSON object to read. + /// The path to the current JSON node. + protected virtual T ReadObject(JObject obj, string path) + { + throw new SParseException($"Can't parse {typeof(T).Name} from object node (path: {path})."); + } + + /// Read a JSON string. + /// The JSON string value. + /// The path to the current JSON node. + protected virtual T ReadString(string str, string path) + { + throw new SParseException($"Can't parse {typeof(T).Name} from string node (path: {path})."); + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/InternalExtensions.cs b/src/SMAPI.Toolkit/Serialization/InternalExtensions.cs new file mode 100644 index 00000000..9aba53bf --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/InternalExtensions.cs @@ -0,0 +1,21 @@ +using System; +using Newtonsoft.Json.Linq; + +namespace StardewModdingAPI.Toolkit.Serialization +{ + /// Provides extension methods for parsing JSON. + public static class JsonExtensions + { + /// Get a JSON field value from a case-insensitive field name. This will check for an exact match first, then search without case sensitivity. + /// The value type. + /// The JSON object to search. + /// The field name. + public static T ValueIgnoreCase(this JObject obj, string fieldName) + { + JToken token = obj.GetValue(fieldName, StringComparison.InvariantCultureIgnoreCase); + return token != null + ? token.Value() + : default(T); + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/JsonHelper.cs b/src/SMAPI.Toolkit/Serialization/JsonHelper.cs new file mode 100644 index 00000000..031afbb0 --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/JsonHelper.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using StardewModdingAPI.Toolkit.Serialization.Converters; + +namespace StardewModdingAPI.Toolkit.Serialization +{ + /// Encapsulates SMAPI's JSON file parsing. + public class JsonHelper + { + /********* + ** Accessors + *********/ + /// The JSON settings to use when serializing and deserializing files. + public JsonSerializerSettings JsonSettings { get; } = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + ObjectCreationHandling = ObjectCreationHandling.Replace, // avoid issue where default ICollection values are duplicated each time the config is loaded + Converters = new List + { + new SemanticVersionConverter(), + new StringEnumConverter() + } + }; + + + /********* + ** Public methods + *********/ + /// Read a JSON file. + /// The model type. + /// The absolute file path. + /// The parsed content model. + /// Returns false if the file doesn't exist, else true. + /// The given is empty or invalid. + /// The file contains invalid JSON. + public bool ReadJsonFileIfExists(string fullPath, out TModel result) + { + // validate + if (string.IsNullOrWhiteSpace(fullPath)) + throw new ArgumentException("The file path is empty or invalid.", nameof(fullPath)); + + // read file + string json; + try + { + json = File.ReadAllText(fullPath); + } + catch (Exception ex) when (ex is DirectoryNotFoundException || ex is FileNotFoundException) + { + result = default(TModel); + return false; + } + + // deserialize model + try + { + result = this.Deserialize(json); + return true; + } + catch (Exception ex) + { + string error = $"Can't parse JSON file at {fullPath}."; + + if (ex is JsonReaderException) + { + error += " This doesn't seem to be valid JSON."; + if (json.Contains("“") || json.Contains("”")) + error += " Found curly quotes in the text; note that only straight quotes are allowed in JSON."; + } + error += $"\nTechnical details: {ex.Message}"; + throw new JsonReaderException(error); + } + } + + /// Save to a JSON file. + /// The model type. + /// The absolute file path. + /// The model to save. + /// The given path is empty or invalid. + public void WriteJsonFile(string fullPath, TModel model) + where TModel : class + { + // validate + if (string.IsNullOrWhiteSpace(fullPath)) + throw new ArgumentException("The file path is empty or invalid.", nameof(fullPath)); + + // create directory if needed + string dir = Path.GetDirectoryName(fullPath); + if (dir == null) + throw new ArgumentException("The file path is invalid.", nameof(fullPath)); + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + + // write file + string json = this.Serialize(model); + File.WriteAllText(fullPath, json); + } + + /// Deserialize JSON text if possible. + /// The model type. + /// The raw JSON text. + public TModel Deserialize(string json) + { + try + { + return JsonConvert.DeserializeObject(json, this.JsonSettings); + } + catch (JsonReaderException) + { + // try replacing curly quotes + if (json.Contains("“") || json.Contains("”")) + { + try + { + return JsonConvert.DeserializeObject(json.Replace('“', '"').Replace('”', '"'), this.JsonSettings); + } + catch { /* rethrow original error */ } + } + + throw; + } + } + + /// Serialize a model to JSON text. + /// The model type. + /// The model to serialize. + /// The formatting to apply. + public string Serialize(TModel model, Formatting formatting = Formatting.Indented) + { + return JsonConvert.SerializeObject(model, formatting, this.JsonSettings); + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs b/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs new file mode 100644 index 00000000..99e85cbd --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/Models/Manifest.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using StardewModdingAPI.Toolkit.Serialization.Converters; + +namespace StardewModdingAPI.Toolkit.Serialization.Models +{ + /// A manifest which describes a mod for SMAPI. + public class Manifest : IManifest + { + /********* + ** Accessors + *********/ + /// The mod name. + public string Name { get; set; } + + /// A brief description of the mod. + public string Description { get; set; } + + /// The mod author's name. + public string Author { get; set; } + + /// The mod version. + public ISemanticVersion Version { get; set; } + + /// The minimum SMAPI version required by this mod, if any. + public ISemanticVersion MinimumApiVersion { get; set; } + + /// The name of the DLL in the directory that has the Entry method. Mutually exclusive with . + public string EntryDll { get; set; } + + /// The mod which will read this as a content pack. Mutually exclusive with . + [JsonConverter(typeof(ManifestContentPackForConverter))] + public IManifestContentPackFor ContentPackFor { get; set; } + + /// The other mods that must be loaded before this mod. + [JsonConverter(typeof(ManifestDependencyArrayConverter))] + public IManifestDependency[] Dependencies { get; set; } + + /// The namespaced mod IDs to query for updates (like Nexus:541). + public string[] UpdateKeys { get; set; } + + /// The unique mod ID. + public string UniqueID { get; set; } + + /// Any manifest fields which didn't match a valid field. + [JsonExtensionData] + public IDictionary ExtraFields { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public Manifest() { } + + /// Construct an instance for a transitional content pack. + /// The unique mod ID. + /// The mod name. + /// The mod author's name. + /// A brief description of the mod. + /// The mod version. + /// The modID which will read this as a content pack. + public Manifest(string uniqueID, string name, string author, string description, ISemanticVersion version, string contentPackFor = null) + { + this.Name = name; + this.Author = author; + this.Description = description; + this.Version = version; + this.UniqueID = uniqueID; + this.UpdateKeys = new string[0]; + this.ContentPackFor = new ManifestContentPackFor { UniqueID = contentPackFor }; + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/Models/ManifestContentPackFor.cs b/src/SMAPI.Toolkit/Serialization/Models/ManifestContentPackFor.cs new file mode 100644 index 00000000..1eb80889 --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/Models/ManifestContentPackFor.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Toolkit.Serialization.Models +{ + /// Indicates which mod can read the content pack represented by the containing manifest. + public class ManifestContentPackFor : IManifestContentPackFor + { + /********* + ** Accessors + *********/ + /// The unique ID of the mod which can read this content pack. + public string UniqueID { get; set; } + + /// The minimum required version (if any). + public ISemanticVersion MinimumVersion { get; set; } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/Models/ManifestDependency.cs b/src/SMAPI.Toolkit/Serialization/Models/ManifestDependency.cs new file mode 100644 index 00000000..00f168f4 --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/Models/ManifestDependency.cs @@ -0,0 +1,35 @@ +namespace StardewModdingAPI.Toolkit.Serialization.Models +{ + /// A mod dependency listed in a mod manifest. + public class ManifestDependency : IManifestDependency + { + /********* + ** Accessors + *********/ + /// The unique mod ID to require. + public string UniqueID { get; set; } + + /// The minimum required version (if any). + public ISemanticVersion MinimumVersion { get; set; } + + /// Whether the dependency must be installed to use the mod. + public bool IsRequired { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The unique mod ID to require. + /// The minimum required version (if any). + /// Whether the dependency must be installed to use the mod. + public ManifestDependency(string uniqueID, string minimumVersion, bool required = true) + { + this.UniqueID = uniqueID; + this.MinimumVersion = !string.IsNullOrWhiteSpace(minimumVersion) + ? new SemanticVersion(minimumVersion) + : null; + this.IsRequired = required; + } + } +} diff --git a/src/SMAPI.Toolkit/Serialization/SParseException.cs b/src/SMAPI.Toolkit/Serialization/SParseException.cs new file mode 100644 index 00000000..5f58b5b8 --- /dev/null +++ b/src/SMAPI.Toolkit/Serialization/SParseException.cs @@ -0,0 +1,17 @@ +using System; + +namespace StardewModdingAPI.Toolkit.Serialization +{ + /// A format exception which provides a user-facing error message. + internal class SParseException : FormatException + { + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The error message. + /// The underlying exception, if any. + public SParseException(string message, Exception ex = null) + : base(message, ex) { } + } +} diff --git a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs index 8a3c2b03..40a59d87 100644 --- a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs +++ b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs @@ -6,7 +6,7 @@ using System.Text.RegularExpressions; namespace StardewModdingAPI.Toolkit.Utilities { - /// Provides utilities for normalising file paths. + /// Provides utilities for normalizing file paths. public static class PathUtilities { /********* @@ -15,14 +15,14 @@ namespace StardewModdingAPI.Toolkit.Utilities /// The possible directory separator characters in a file path. private static readonly char[] PossiblePathSeparators = new[] { '/', '\\', Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.Distinct().ToArray(); - /// The preferred directory separator chaeacter in an asset key. + /// The preferred directory separator character in an asset key. private static readonly string PreferredPathSeparator = Path.DirectorySeparatorChar.ToString(); /********* ** Public methods *********/ - /// Get the segments from a path (e.g. /usr/bin/boop => usr, bin, and boop). + /// Get the segments from a path (e.g. /usr/bin/example => usr, bin, and example). /// The path to split. /// The number of segments to match. Any additional segments will be merged into the last returned part. public static string[] GetSegments(string path, int? limit = null) @@ -32,16 +32,16 @@ namespace StardewModdingAPI.Toolkit.Utilities : path.Split(PathUtilities.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries); } - /// Normalise path separators in a file path. - /// The file path to normalise. + /// Normalize path separators in a file path. + /// The file path to normalize. [Pure] - public static string NormalisePathSeparators(string path) + public static string NormalizePathSeparators(string path) { string[] parts = PathUtilities.GetSegments(path); - string normalised = string.Join(PathUtilities.PreferredPathSeparator, parts); + string normalized = string.Join(PathUtilities.PreferredPathSeparator, parts); if (path.StartsWith(PathUtilities.PreferredPathSeparator)) - normalised = PathUtilities.PreferredPathSeparator + normalised; // keep root slash - return normalised; + normalized = PathUtilities.PreferredPathSeparator + normalized; // keep root slash + return normalized; } /// Get a directory or file path relative to a given source path. @@ -57,7 +57,7 @@ namespace StardewModdingAPI.Toolkit.Utilities throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{sourceDir}'."); // get relative path - string relative = PathUtilities.NormalisePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString())); + string relative = PathUtilities.NormalizePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString())); if (relative == "") relative = "./"; return relative; diff --git a/src/SMAPI.Web/BackgroundService.cs b/src/SMAPI.Web/BackgroundService.cs index dfd2c1b9..cb400fbe 100644 --- a/src/SMAPI.Web/BackgroundService.cs +++ b/src/SMAPI.Web/BackgroundService.cs @@ -11,7 +11,7 @@ using StardewModdingAPI.Web.Framework.Caching.Wiki; namespace StardewModdingAPI.Web { /// A hosted service which runs background data updates. - /// Task methods need to be static, since otherwise Hangfire will try to serialise the entire instance. + /// Task methods need to be static, since otherwise Hangfire will try to serialize the entire instance. internal class BackgroundService : IHostedService, IDisposable { /********* @@ -94,8 +94,8 @@ namespace StardewModdingAPI.Web /********* ** Private method *********/ - /// Initialise the background service if it's not already initialised. - /// The background service is already initialised. + /// Initialize the background service if it's not already initialized. + /// The background service is already initialized. private void TryInit() { if (BackgroundService.JobServer != null) diff --git a/src/SMAPI.Web/Controllers/JsonValidatorController.cs b/src/SMAPI.Web/Controllers/JsonValidatorController.cs index d82765e7..31471141 100644 --- a/src/SMAPI.Web/Controllers/JsonValidatorController.cs +++ b/src/SMAPI.Web/Controllers/JsonValidatorController.cs @@ -79,7 +79,7 @@ namespace StardewModdingAPI.Web.Controllers [Route("json/{schemaName}/{id}")] public async Task Index(string schemaName = null, string id = null) { - schemaName = this.NormaliseSchemaName(schemaName); + schemaName = this.NormalizeSchemaName(schemaName); var result = new JsonValidatorModel(this.SectionUrl, id, schemaName, this.SchemaFormats); if (string.IsNullOrWhiteSpace(id)) @@ -143,8 +143,8 @@ namespace StardewModdingAPI.Web.Controllers if (request == null) return this.View("Index", new JsonValidatorModel(this.SectionUrl, null, null, this.SchemaFormats).SetUploadError("The request seems to be invalid.")); - // normalise schema name - string schemaName = this.NormaliseSchemaName(request.SchemaName); + // normalize schema name + string schemaName = this.NormalizeSchemaName(request.SchemaName); // get raw log text string input = request.Content; @@ -178,9 +178,9 @@ namespace StardewModdingAPI.Web.Controllers return response; } - /// Get a normalised schema name, or the if blank. - /// The raw schema name to normalise. - private string NormaliseSchemaName(string schemaName) + /// Get a normalized schema name, or the if blank. + /// The raw schema name to normalize. + private string NormalizeSchemaName(string schemaName) { schemaName = schemaName?.Trim().ToLower(); return !string.IsNullOrWhiteSpace(schemaName) @@ -192,7 +192,7 @@ namespace StardewModdingAPI.Web.Controllers /// The schema ID. private FileInfo FindSchemaFile(string id) { - // normalise ID + // normalize ID id = id?.Trim().ToLower(); if (string.IsNullOrWhiteSpace(id)) return null; diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index a7398eee..8419b220 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -120,7 +120,7 @@ namespace StardewModdingAPI.Web.Controllers /// Returns the mod data if found, else null. private async Task GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata) { - // crossreference data + // cross-reference data ModDataRecord record = this.ModDatabase.Get(search.ID); WikiModEntry wikiEntry = wikiData.FirstOrDefault(entry => entry.ID.Contains(search.ID.Trim(), StringComparer.InvariantCultureIgnoreCase)); UpdateKey[] updateKeys = this.GetUpdateKeys(search.UpdateKeys, record, wikiEntry).ToArray(); diff --git a/src/SMAPI.Web/Framework/AllowLargePostsAttribute.cs b/src/SMAPI.Web/Framework/AllowLargePostsAttribute.cs index 5dc0feb6..864aa215 100644 --- a/src/SMAPI.Web/Framework/AllowLargePostsAttribute.cs +++ b/src/SMAPI.Web/Framework/AllowLargePostsAttribute.cs @@ -36,7 +36,7 @@ namespace StardewModdingAPI.Web.Framework } /// Called early in the filter pipeline to confirm request is authorized. - /// The authorisation filter context. + /// The authorization filter context. public void OnAuthorization(AuthorizationFilterContext context) { IFeatureCollection features = context.HttpContext.Features; diff --git a/src/SMAPI.Web/Framework/Caching/Mods/ModCacheRepository.cs b/src/SMAPI.Web/Framework/Caching/Mods/ModCacheRepository.cs index 4258cc85..2e7804a7 100644 --- a/src/SMAPI.Web/Framework/Caching/Mods/ModCacheRepository.cs +++ b/src/SMAPI.Web/Framework/Caching/Mods/ModCacheRepository.cs @@ -40,7 +40,7 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods public bool TryGetMod(ModRepositoryKey site, string id, out CachedMod mod, bool markRequested = true) { // get mod - id = this.NormaliseId(id); + id = this.NormalizeId(id); mod = this.Mods.Find(entry => entry.ID == id && entry.Site == site).FirstOrDefault(); if (mod == null) return false; @@ -62,7 +62,7 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods /// The stored mod record. public void SaveMod(ModRepositoryKey site, string id, ModInfoModel mod, out CachedMod cachedMod) { - id = this.NormaliseId(id); + id = this.NormalizeId(id); cachedMod = this.SaveMod(new CachedMod(site, id, mod)); } @@ -83,7 +83,7 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods /// The mod data. public CachedMod SaveMod(CachedMod mod) { - string id = this.NormaliseId(mod.ID); + string id = this.NormalizeId(mod.ID); this.Mods.ReplaceOne( entry => entry.ID == id && entry.Site == mod.Site, @@ -94,9 +94,9 @@ namespace StardewModdingAPI.Web.Framework.Caching.Mods return mod; } - /// Normalise a mod ID for case-insensitive search. + /// Normalize a mod ID for case-insensitive search. /// The mod ID. - public string NormaliseId(string id) + public string NormalizeId(string id) { return id.Trim().ToLower(); } diff --git a/src/SMAPI.Web/Framework/Caching/UtcDateTimeOffsetSerializer.cs b/src/SMAPI.Web/Framework/Caching/UtcDateTimeOffsetSerializer.cs index ad95a975..6a103e37 100644 --- a/src/SMAPI.Web/Framework/Caching/UtcDateTimeOffsetSerializer.cs +++ b/src/SMAPI.Web/Framework/Caching/UtcDateTimeOffsetSerializer.cs @@ -5,7 +5,7 @@ using MongoDB.Bson.Serialization.Serializers; namespace StardewModdingAPI.Web.Framework.Caching { - /// Serialises to a UTC date field instead of the default array. + /// Serializes to a UTC date field instead of the default array. public class UtcDateTimeOffsetSerializer : StructSerializerBase { /********* diff --git a/src/SMAPI.Web/Framework/JobDashboardAuthorizationFilter.cs b/src/SMAPI.Web/Framework/JobDashboardAuthorizationFilter.cs index 9471d5fe..385c0c91 100644 --- a/src/SMAPI.Web/Framework/JobDashboardAuthorizationFilter.cs +++ b/src/SMAPI.Web/Framework/JobDashboardAuthorizationFilter.cs @@ -2,7 +2,7 @@ using Hangfire.Dashboard; namespace StardewModdingAPI.Web.Framework { - /// Authorises requests to access the Hangfire job dashboard. + /// Authorizes requests to access the Hangfire job dashboard. internal class JobDashboardAuthorizationFilter : IDashboardAuthorizationFilter { /********* @@ -15,7 +15,7 @@ namespace StardewModdingAPI.Web.Framework /********* ** Public methods *********/ - /// Authorise a request. + /// Authorize a request. /// The dashboard context. public bool Authorize(DashboardContext context) { diff --git a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs index 595e6b49..66a3687f 100644 --- a/src/SMAPI.Web/Framework/LogParsing/LogParser.cs +++ b/src/SMAPI.Web/Framework/LogParsing/LogParser.cs @@ -221,7 +221,7 @@ namespace StardewModdingAPI.Web.Framework.LogParsing } } - // finalise log + // finalize log gameMod.Version = log.GameVersion; log.Mods = new[] { gameMod, smapiMod }.Concat(mods.Values.OrderBy(p => p.Name)).ToArray(); return log; diff --git a/src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs index 94256005..f9f9f47d 100644 --- a/src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs +++ b/src/SMAPI.Web/Framework/ModRepositories/BaseRepository.cs @@ -34,9 +34,9 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories this.VendorKey = vendorKey; } - /// Normalise a version string. - /// The version to normalise. - protected string NormaliseVersion(string version) + /// Normalize a version string. + /// The version to normalize. + protected string NormalizeVersion(string version) { if (string.IsNullOrWhiteSpace(version)) return null; diff --git a/src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs index c14fb45d..0945735a 100644 --- a/src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs +++ b/src/SMAPI.Web/Framework/ModRepositories/ChucklefishRepository.cs @@ -39,7 +39,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories { var mod = await this.Client.GetModAsync(realID); return mod != null - ? new ModInfoModel(name: mod.Name, version: this.NormaliseVersion(mod.Version), url: mod.Url) + ? new ModInfoModel(name: mod.Name, version: this.NormalizeVersion(mod.Version), url: mod.Url) : new ModInfoModel().SetError(RemoteModStatus.DoesNotExist, "Found no Chucklefish mod with this ID."); } catch (Exception ex) diff --git a/src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs index e06a2497..c62cb73f 100644 --- a/src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs +++ b/src/SMAPI.Web/Framework/ModRepositories/GitHubRepository.cs @@ -65,7 +65,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories } // return data - return result.SetVersions(version: this.NormaliseVersion(latest.Tag), previewVersion: this.NormaliseVersion(preview?.Tag)); + return result.SetVersions(version: this.NormalizeVersion(latest.Tag), previewVersion: this.NormalizeVersion(preview?.Tag)); } catch (Exception ex) { diff --git a/src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs index b4791f56..9551258c 100644 --- a/src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs +++ b/src/SMAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -48,7 +48,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories return new ModInfoModel().SetError(remoteStatus, mod.Error); } - return new ModInfoModel(name: mod.Name, version: this.NormaliseVersion(mod.Version), previewVersion: mod.LatestFileVersion?.ToString(), url: mod.Url); + return new ModInfoModel(name: mod.Name, version: this.NormalizeVersion(mod.Version), previewVersion: mod.LatestFileVersion?.ToString(), url: mod.Url); } catch (Exception ex) { diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index de45b8a4..da5c1f1b 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -10,7 +10,7 @@ using Microsoft.Extensions.DependencyInjection; using MongoDB.Bson.Serialization; using MongoDB.Driver; using Newtonsoft.Json; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Web.Framework; using StardewModdingAPI.Web.Framework.Caching; using StardewModdingAPI.Web.Framework.Caching.Mods; diff --git a/src/SMAPI.Web/ViewModels/LogParserModel.cs b/src/SMAPI.Web/ViewModels/LogParserModel.cs index 41864c99..25493a29 100644 --- a/src/SMAPI.Web/ViewModels/LogParserModel.cs +++ b/src/SMAPI.Web/ViewModels/LogParserModel.cs @@ -81,7 +81,7 @@ namespace StardewModdingAPI.Web.ViewModels .ToDictionary(group => group.Key, group => group.ToArray()); } - /// Get a sanitised mod name that's safe to use in anchors, attributes, and URLs. + /// Get a sanitized mod name that's safe to use in anchors, attributes, and URLs. /// The mod name. public string GetSlug(string modName) { diff --git a/src/SMAPI.Web/wwwroot/Content/js/json-validator.js b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js index 265e0c5e..5499cef6 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/json-validator.js +++ b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js @@ -120,7 +120,7 @@ smapi.jsonValidator = function (sectionUrl, pasteID) { }; /** - * Initialise the JSON validator page. + * Initialize the JSON validator page. */ var init = function () { // set initial code formatting diff --git a/src/SMAPI.Web/wwwroot/schemas/content-patcher.json b/src/SMAPI.Web/wwwroot/schemas/content-patcher.json index 315a1fb2..e12be408 100644 --- a/src/SMAPI.Web/wwwroot/schemas/content-patcher.json +++ b/src/SMAPI.Web/wwwroot/schemas/content-patcher.json @@ -107,7 +107,7 @@ }, "Target": { "title": "Target asset", - "description": "The game asset you want to patch (or multiple comma-delimited assets). This is the file path inside your game's Content folder, without the file extension or language (like Animals/Dinosaur to edit Content/Animals/Dinosaur.xnb). This field supports tokens and capitalisation doesn't matter. Your changes are applied in all languages unless you specify a language condition.", + "description": "The game asset you want to patch (or multiple comma-delimited assets). This is the file path inside your game's Content folder, without the file extension or language (like Animals/Dinosaur to edit Content/Animals/Dinosaur.xnb). This field supports tokens and capitalization doesn't matter. Your changes are applied in all languages unless you specify a language condition.", "type": "string", "not": { "pattern": "^ *[cC][oO][nN][tT][eE][nN][tT]/|\\.[xX][nN][bB] *$|\\.[a-zA-Z][a-zA-Z]-[a-zA-Z][a-zA-Z](?:.xnb)? *$" @@ -140,7 +140,7 @@ }, "FromFile": { "title": "Source file", - "description": "The relative file path in your content pack folder to load instead (like 'assets/dinosaur.png'). This can be a .json (data), .png (image), .tbin (map), or .xnb file. This field supports tokens and capitalisation doesn't matter.", + "description": "The relative file path in your content pack folder to load instead (like 'assets/dinosaur.png'). This can be a .json (data), .png (image), .tbin (map), or .xnb file. This field supports tokens and capitalization doesn't matter.", "type": "string", "allOf": [ { @@ -310,7 +310,7 @@ "then": { "properties": { "FromFile": { - "description": "The relative path to the map in your content pack folder from which to copy (like assets/town.tbin). This can be a .tbin or .xnb file. This field supports tokens and capitalisation doesn't matter.\nContent Patcher will handle tilesheets referenced by the FromFile map for you if it's a .tbin file:\n - If a tilesheet isn't referenced by the target map, Content Patcher will add it for you (with a z_ ID prefix to avoid conflicts with hardcoded game logic). If the source map has a custom version of a tilesheet that's already referenced, it'll be added as a separate tilesheet only used by your tiles.\n - If you include the tilesheet file in your mod folder, Content Patcher will use that one automatically; otherwise it will be loaded from the game's Content/Maps folder." + "description": "The relative path to the map in your content pack folder from which to copy (like assets/town.tbin). This can be a .tbin or .xnb file. This field supports tokens and capitalization doesn't matter.\nContent Patcher will handle tilesheets referenced by the FromFile map for you if it's a .tbin file:\n - If a tilesheet isn't referenced by the target map, Content Patcher will add it for you (with a z_ ID prefix to avoid conflicts with hardcoded game logic). If the source map has a custom version of a tilesheet that's already referenced, it'll be added as a separate tilesheet only used by your tiles.\n - If you include the tilesheet file in your mod folder, Content Patcher will use that one automatically; otherwise it will be loaded from the game's Content/Maps folder." }, "FromArea": { "description": "The part of the source map to copy. Defaults to the whole source map." diff --git a/src/SMAPI.sln.DotSettings b/src/SMAPI.sln.DotSettings index 5f67fd9e..556f1ec0 100644 --- a/src/SMAPI.sln.DotSettings +++ b/src/SMAPI.sln.DotSettings @@ -23,4 +23,46 @@ True True True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/src/SMAPI/Context.cs b/src/SMAPI/Context.cs index a933752d..a7238b32 100644 --- a/src/SMAPI/Context.cs +++ b/src/SMAPI/Context.cs @@ -14,10 +14,10 @@ namespace StardewModdingAPI /**** ** Public ****/ - /// Whether the game has performed core initialisation. This becomes true right before the first update tick.. + /// Whether the game has performed core initialization. This becomes true right before the first update tick. public static bool IsGameLaunched { get; internal set; } - /// Whether the player has loaded a save and the world has finished initialising. + /// Whether the player has loaded a save and the world has finished initializing. public static bool IsWorldReady { get; internal set; } /// Whether is true and the player is free to act in the world (no menu is displayed, no cutscene is in progress, etc). diff --git a/src/SMAPI/Enums/LoadStage.cs b/src/SMAPI/Enums/LoadStage.cs index 6ff7de4f..5c2b0412 100644 --- a/src/SMAPI/Enums/LoadStage.cs +++ b/src/SMAPI/Enums/LoadStage.cs @@ -6,10 +6,10 @@ namespace StardewModdingAPI.Enums /// A save is not loaded or loading. None, - /// The game is creating a new save slot, and has initialised the basic save info. + /// 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 initialised the in-game locations. + /// The game is creating a new save slot, and has initialized the in-game locations. CreatedLocations, /// The game is creating a new save slot, and has created the physical save files. @@ -18,7 +18,7 @@ namespace StardewModdingAPI.Enums /// The game is loading a save slot, and has read the raw save data into . Not applicable when connecting to a multiplayer host. This is equivalent to value 20. SaveParsed, - /// 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 initialised at this point. This is equivalent to value 36. + /// 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 applied the in-game location data. Not applicable when connecting to a multiplayer host. This is equivalent to value 50. @@ -27,10 +27,10 @@ namespace StardewModdingAPI.Enums /// The final metadata has been loaded from the save file. This happens before the game applies problem fixes, checks for achievements, starts music, etc. Not applicable when connecting to a multiplayer host. Preloaded, - /// The save is fully loaded, but the world may not be fully initialised yet. + /// The save is fully loaded, but the world may not be fully initialized yet. Loaded, - /// The save is fully loaded, the world has been initialised, and is now true. + /// The save is fully loaded, the world has been initialized, and is now true. Ready } } diff --git a/src/SMAPI/Events/IGameLoopEvents.cs b/src/SMAPI/Events/IGameLoopEvents.cs index 6fb56c8b..a576895b 100644 --- a/src/SMAPI/Events/IGameLoopEvents.cs +++ b/src/SMAPI/Events/IGameLoopEvents.cs @@ -5,7 +5,7 @@ namespace StardewModdingAPI.Events /// Events linked to the game's update loop. The update loop runs roughly ≈60 times/second to run game logic like state changes, action handling, etc. These can be useful, but you should consider more semantic events like if possible. public interface IGameLoopEvents { - /// Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialised at this point, so this is a good time to set up mod integrations. + /// Raised after the game is launched, right before the first update tick. This happens once per game session (unrelated to loading saves). All mods are loaded and initialized at this point, so this is a good time to set up mod integrations. event EventHandler GameLaunched; /// Raised before the game state is updated (≈60 times per second). @@ -32,7 +32,7 @@ namespace StardewModdingAPI.Events /// Raised after the game finishes writing data to the save file (except the initial save creation). event EventHandler Saved; - /// Raised after the player loads a save slot and the world is initialised. + /// Raised after the player loads a save slot and the world is initialized. event EventHandler SaveLoaded; /// Raised after the game begins a new day (including when the player loads a save). diff --git a/src/SMAPI/Events/IModEvents.cs b/src/SMAPI/Events/IModEvents.cs index bd7ab880..1f892b31 100644 --- a/src/SMAPI/Events/IModEvents.cs +++ b/src/SMAPI/Events/IModEvents.cs @@ -21,7 +21,7 @@ namespace StardewModdingAPI.Events /// Events raised when something changes in the world. IWorldEvents World { get; } - /// Events serving specialised edge cases that shouldn't be used by most mods. - ISpecialisedEvents Specialised { get; } + /// Events serving specialized edge cases that shouldn't be used by most mods. + ISpecializedEvents Specialized { get; } } } diff --git a/src/SMAPI/Events/ISpecialisedEvents.cs b/src/SMAPI/Events/ISpecialisedEvents.cs index ecb109e6..bf70956d 100644 --- a/src/SMAPI/Events/ISpecialisedEvents.cs +++ b/src/SMAPI/Events/ISpecialisedEvents.cs @@ -2,8 +2,8 @@ using System; namespace StardewModdingAPI.Events { - /// Events serving specialised edge cases that shouldn't be used by most mods. - public interface ISpecialisedEvents + /// Events serving specialized edge cases that shouldn't be used by most mods. + public interface ISpecializedEvents { /// Raised when the low-level stage in the game's loading process has changed. This is an advanced event for mods which need to run code at specific points in the loading process. The available stages or when they happen might change without warning in future versions (e.g. due to changes in the game's load process), so mods using this event are more likely to break or have bugs. Most mods should use instead. event EventHandler LoadStageChanged; diff --git a/src/SMAPI/Events/LoadStageChangedEventArgs.cs b/src/SMAPI/Events/LoadStageChangedEventArgs.cs index e837a5f1..3529dcf3 100644 --- a/src/SMAPI/Events/LoadStageChangedEventArgs.cs +++ b/src/SMAPI/Events/LoadStageChangedEventArgs.cs @@ -3,7 +3,7 @@ using StardewModdingAPI.Enums; namespace StardewModdingAPI.Events { - /// Event arguments for an event. + /// Event arguments for an event. public class LoadStageChangedEventArgs : EventArgs { /********* diff --git a/src/SMAPI/Events/UnvalidatedUpdateTickedEventArgs.cs b/src/SMAPI/Events/UnvalidatedUpdateTickedEventArgs.cs index 13c367a0..258e2f99 100644 --- a/src/SMAPI/Events/UnvalidatedUpdateTickedEventArgs.cs +++ b/src/SMAPI/Events/UnvalidatedUpdateTickedEventArgs.cs @@ -3,7 +3,7 @@ using StardewModdingAPI.Framework; namespace StardewModdingAPI.Events { - /// Event arguments for an event. + /// Event arguments for an event. public class UnvalidatedUpdateTickedEventArgs : EventArgs { /********* diff --git a/src/SMAPI/Events/UnvalidatedUpdateTickingEventArgs.cs b/src/SMAPI/Events/UnvalidatedUpdateTickingEventArgs.cs index c2e60f25..e3c8b3ee 100644 --- a/src/SMAPI/Events/UnvalidatedUpdateTickingEventArgs.cs +++ b/src/SMAPI/Events/UnvalidatedUpdateTickingEventArgs.cs @@ -3,7 +3,7 @@ using StardewModdingAPI.Framework; namespace StardewModdingAPI.Events { - /// Event arguments for an event. + /// Event arguments for an event. public class UnvalidatedUpdateTickingEventArgs : EventArgs { /********* diff --git a/src/SMAPI/Framework/CommandManager.cs b/src/SMAPI/Framework/CommandManager.cs index fdaafff1..ceeb6f93 100644 --- a/src/SMAPI/Framework/CommandManager.cs +++ b/src/SMAPI/Framework/CommandManager.cs @@ -29,7 +29,7 @@ namespace StardewModdingAPI.Framework /// There's already a command with that name. public void Add(IModMetadata mod, string name, string documentation, Action callback, bool allowNullCallback = false) { - name = this.GetNormalisedName(name); + name = this.GetNormalizedName(name); // validate format if (string.IsNullOrWhiteSpace(name)) @@ -52,7 +52,7 @@ namespace StardewModdingAPI.Framework /// Returns the matching command, or null if not found. public Command Get(string name) { - name = this.GetNormalisedName(name); + name = this.GetNormalizedName(name); this.Commands.TryGetValue(name, out Command command); return command; } @@ -84,7 +84,7 @@ namespace StardewModdingAPI.Framework // parse input args = this.ParseArgs(input); - name = this.GetNormalisedName(args[0]); + name = this.GetNormalizedName(args[0]); args = args.Skip(1).ToArray(); // get command @@ -97,8 +97,8 @@ namespace StardewModdingAPI.Framework /// Returns whether a matching command was triggered. public bool Trigger(string name, string[] arguments) { - // get normalised name - name = this.GetNormalisedName(name); + // get normalized name + name = this.GetNormalizedName(name); if (name == null) return false; @@ -140,9 +140,9 @@ namespace StardewModdingAPI.Framework return args.Where(item => !string.IsNullOrWhiteSpace(item)).ToArray(); } - /// Get a normalised command name. + /// Get a normalized command name. /// The command name. - private string GetNormalisedName(string name) + private string GetNormalizedName(string name) { name = name?.Trim().ToLower(); return !string.IsNullOrWhiteSpace(name) diff --git a/src/SMAPI/Framework/Content/AssetData.cs b/src/SMAPI/Framework/Content/AssetData.cs index 553404d3..cacc6078 100644 --- a/src/SMAPI/Framework/Content/AssetData.cs +++ b/src/SMAPI/Framework/Content/AssetData.cs @@ -24,13 +24,13 @@ namespace StardewModdingAPI.Framework.Content ** Public methods *********/ /// Construct an instance. - /// The content's locale code, if the content is localised. - /// The normalised asset name being read. + /// The content's locale code, if the content is localized. + /// The normalized asset name being read. /// The content data being read. - /// Normalises an asset key to match the cache key. + /// Normalizes an asset key to match the cache key. /// A callback to invoke when the data is replaced (if any). - public AssetData(string locale, string assetName, TValue data, Func getNormalisedPath, Action onDataReplaced) - : base(locale, assetName, data.GetType(), getNormalisedPath) + public AssetData(string locale, string assetName, TValue data, Func getNormalizedPath, Action onDataReplaced) + : base(locale, assetName, data.GetType(), getNormalizedPath) { this.Data = data; this.OnDataReplaced = onDataReplaced; diff --git a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs index a331f38a..26cbff5a 100644 --- a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs +++ b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs @@ -10,12 +10,12 @@ namespace StardewModdingAPI.Framework.Content ** Public methods *********/ /// Construct an instance. - /// The content's locale code, if the content is localised. - /// The normalised asset name being read. + /// The content's locale code, if the content is localized. + /// The normalized asset name being read. /// The content data being read. - /// Normalises an asset key to match the cache key. + /// Normalizes an asset key to match the cache key. /// A callback to invoke when the data is replaced (if any). - public AssetDataForDictionary(string locale, string assetName, IDictionary data, Func getNormalisedPath, Action> onDataReplaced) - : base(locale, assetName, data, getNormalisedPath, onDataReplaced) { } + public AssetDataForDictionary(string locale, string assetName, IDictionary data, Func getNormalizedPath, Action> onDataReplaced) + : base(locale, assetName, data, getNormalizedPath, onDataReplaced) { } } } diff --git a/src/SMAPI/Framework/Content/AssetDataForImage.cs b/src/SMAPI/Framework/Content/AssetDataForImage.cs index f2d21b5e..4ae2ad68 100644 --- a/src/SMAPI/Framework/Content/AssetDataForImage.cs +++ b/src/SMAPI/Framework/Content/AssetDataForImage.cs @@ -19,13 +19,13 @@ namespace StardewModdingAPI.Framework.Content ** Public methods *********/ /// Construct an instance. - /// The content's locale code, if the content is localised. - /// The normalised asset name being read. + /// The content's locale code, if the content is localized. + /// The normalized asset name being read. /// The content data being read. - /// Normalises an asset key to match the cache key. + /// Normalizes an asset key to match the cache key. /// A callback to invoke when the data is replaced (if any). - public AssetDataForImage(string locale, string assetName, Texture2D data, Func getNormalisedPath, Action onDataReplaced) - : base(locale, assetName, data, getNormalisedPath, onDataReplaced) { } + public AssetDataForImage(string locale, string assetName, Texture2D data, Func getNormalizedPath, Action onDataReplaced) + : base(locale, assetName, data, getNormalizedPath, onDataReplaced) { } /// Overwrite part of the image. /// The image to patch into the content. diff --git a/src/SMAPI/Framework/Content/AssetDataForObject.cs b/src/SMAPI/Framework/Content/AssetDataForObject.cs index 90f9e2d4..4dbc988c 100644 --- a/src/SMAPI/Framework/Content/AssetDataForObject.cs +++ b/src/SMAPI/Framework/Content/AssetDataForObject.cs @@ -11,19 +11,19 @@ namespace StardewModdingAPI.Framework.Content ** Public methods *********/ /// Construct an instance. - /// The content's locale code, if the content is localised. - /// The normalised asset name being read. + /// The content's locale code, if the content is localized. + /// The normalized asset name being read. /// The content data being read. - /// Normalises an asset key to match the cache key. - public AssetDataForObject(string locale, string assetName, object data, Func getNormalisedPath) - : base(locale, assetName, data, getNormalisedPath, onDataReplaced: null) { } + /// Normalizes an asset key to match the cache key. + public AssetDataForObject(string locale, string assetName, object data, Func getNormalizedPath) + : base(locale, assetName, data, getNormalizedPath, onDataReplaced: null) { } /// Construct an instance. /// The asset metadata. /// The content data being read. - /// Normalises an asset key to match the cache key. - public AssetDataForObject(IAssetInfo info, object data, Func getNormalisedPath) - : this(info.Locale, info.AssetName, data, getNormalisedPath) { } + /// Normalizes an asset key to match the cache key. + public AssetDataForObject(IAssetInfo info, object data, Func getNormalizedPath) + : this(info.Locale, info.AssetName, data, getNormalizedPath) { } /// Get a helper to manipulate the data as a dictionary. /// The expected dictionary key. @@ -31,14 +31,14 @@ namespace StardewModdingAPI.Framework.Content /// The content being read isn't a dictionary. public IAssetDataForDictionary AsDictionary() { - return new AssetDataForDictionary(this.Locale, this.AssetName, this.GetData>(), this.GetNormalisedPath, this.ReplaceWith); + return new AssetDataForDictionary(this.Locale, this.AssetName, this.GetData>(), this.GetNormalizedPath, this.ReplaceWith); } /// Get a helper to manipulate the data as an image. /// The content being read isn't an image. public IAssetDataForImage AsImage() { - return new AssetDataForImage(this.Locale, this.AssetName, this.GetData(), this.GetNormalisedPath, this.ReplaceWith); + return new AssetDataForImage(this.Locale, this.AssetName, this.GetData(), this.GetNormalizedPath, this.ReplaceWith); } /// Get the data as a given type. diff --git a/src/SMAPI/Framework/Content/AssetInfo.cs b/src/SMAPI/Framework/Content/AssetInfo.cs index e5211290..9b685e72 100644 --- a/src/SMAPI/Framework/Content/AssetInfo.cs +++ b/src/SMAPI/Framework/Content/AssetInfo.cs @@ -9,17 +9,17 @@ namespace StardewModdingAPI.Framework.Content /********* ** Fields *********/ - /// Normalises an asset key to match the cache key. - protected readonly Func GetNormalisedPath; + /// Normalizes an asset key to match the cache key. + protected readonly Func GetNormalizedPath; /********* ** Accessors *********/ - /// The content's locale code, if the content is localised. + /// The content's locale code, if the content is localized. public string Locale { get; } - /// The normalised asset name being read. The format may change between platforms; see to compare with a known path. + /// The normalized asset name being read. The format may change between platforms; see to compare with a known path. public string AssetName { get; } /// The content data type. @@ -30,23 +30,23 @@ namespace StardewModdingAPI.Framework.Content ** Public methods *********/ /// Construct an instance. - /// The content's locale code, if the content is localised. - /// The normalised asset name being read. + /// The content's locale code, if the content is localized. + /// The normalized asset name being read. /// The content type being read. - /// Normalises an asset key to match the cache key. - public AssetInfo(string locale, string assetName, Type type, Func getNormalisedPath) + /// Normalizes an asset key to match the cache key. + public AssetInfo(string locale, string assetName, Type type, Func getNormalizedPath) { this.Locale = locale; this.AssetName = assetName; this.DataType = type; - this.GetNormalisedPath = getNormalisedPath; + this.GetNormalizedPath = getNormalizedPath; } - /// Get whether the asset name being loaded matches a given name after normalisation. + /// Get whether the asset name being loaded matches a given name after normalization. /// The expected asset path, relative to the game's content folder and without the .xnb extension or locale suffix (like 'Data\ObjectInformation'). public bool AssetNameEquals(string path) { - path = this.GetNormalisedPath(path); + path = this.GetNormalizedPath(path); return this.AssetName.Equals(path, StringComparison.InvariantCultureIgnoreCase); } diff --git a/src/SMAPI/Framework/Content/ContentCache.cs b/src/SMAPI/Framework/Content/ContentCache.cs index 55a96ed2..4178b663 100644 --- a/src/SMAPI/Framework/Content/ContentCache.cs +++ b/src/SMAPI/Framework/Content/ContentCache.cs @@ -10,7 +10,7 @@ using StardewValley; namespace StardewModdingAPI.Framework.Content { - /// A low-level wrapper around the content cache which handles reading, writing, and invalidating entries in the cache. This doesn't handle any higher-level logic like localisation, loading content, etc. It assumes all keys passed in are already normalised. + /// A low-level wrapper around the content cache which handles reading, writing, and invalidating entries in the cache. This doesn't handle any higher-level logic like localization, loading content, etc. It assumes all keys passed in are already normalized. internal class ContentCache { /********* @@ -19,8 +19,8 @@ namespace StardewModdingAPI.Framework.Content /// The underlying asset cache. private readonly IDictionary Cache; - /// Applies platform-specific asset key normalisation so it's consistent with the underlying cache. - private readonly Func NormaliseAssetNameForPlatform; + /// Applies platform-specific asset key normalization so it's consistent with the underlying cache. + private readonly Func NormalizeAssetNameForPlatform; /********* @@ -52,14 +52,14 @@ namespace StardewModdingAPI.Framework.Content // init this.Cache = reflection.GetField>(contentManager, "loadedAssets").GetValue(); - // get key normalisation logic + // get key normalization logic if (Constants.Platform == Platform.Windows) { IReflectedMethod method = reflection.GetMethod(typeof(TitleContainer), "GetCleanPath"); - this.NormaliseAssetNameForPlatform = path => method.Invoke(path); + this.NormalizeAssetNameForPlatform = path => method.Invoke(path); } else - this.NormaliseAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load logic + this.NormalizeAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load logic } /**** @@ -74,25 +74,25 @@ namespace StardewModdingAPI.Framework.Content /**** - ** Normalise + ** Normalize ****/ - /// Normalise path separators in a file path. For asset keys, see instead. - /// The file path to normalise. + /// Normalize path separators in a file path. For asset keys, see instead. + /// The file path to normalize. [Pure] - public string NormalisePathSeparators(string path) + public string NormalizePathSeparators(string path) { - return PathUtilities.NormalisePathSeparators(path); + return PathUtilities.NormalizePathSeparators(path); } - /// Normalise a cache key so it's consistent with the underlying cache. + /// Normalize a cache key so it's consistent with the underlying cache. /// The asset key. [Pure] - public string NormaliseKey(string key) + public string NormalizeKey(string key) { - key = this.NormalisePathSeparators(key); + key = this.NormalizePathSeparators(key); return key.EndsWith(".xnb", StringComparison.InvariantCultureIgnoreCase) ? key.Substring(0, key.Length - 4) - : this.NormaliseAssetNameForPlatform(key); + : this.NormalizeAssetNameForPlatform(key); } /**** diff --git a/src/SMAPI/Framework/ContentCoordinator.cs b/src/SMAPI/Framework/ContentCoordinator.cs index 39bebdd1..08ebe6a5 100644 --- a/src/SMAPI/Framework/ContentCoordinator.cs +++ b/src/SMAPI/Framework/ContentCoordinator.cs @@ -9,7 +9,7 @@ using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.ContentManagers; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Metadata; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; @@ -74,7 +74,7 @@ namespace StardewModdingAPI.Framework /// Construct an instance. /// The service provider to use to locate services. /// The root directory to search for content. - /// The current culture for which to localise content. + /// The current culture for which to localize content. /// Encapsulates monitoring and logging. /// Simplifies access to private code. /// Encapsulates SMAPI's JSON file parsing. @@ -89,7 +89,7 @@ namespace StardewModdingAPI.Framework this.ContentManagers.Add( this.MainContentManager = new GameContentManager("Game1.content", serviceProvider, rootDirectory, currentCulture, this, monitor, reflection, this.OnDisposing, onLoadingFirstAsset) ); - this.CoreAssets = new CoreAssetPropagator(this.MainContentManager.AssertAndNormaliseAssetName, reflection, monitor); + this.CoreAssets = new CoreAssetPropagator(this.MainContentManager.AssertAndNormalizeAssetName, reflection, monitor); } /// Get a new content manager which handles reading files from the game content folder with support for interception. @@ -250,7 +250,7 @@ namespace StardewModdingAPI.Framework string locale = this.GetLocale(); return this.InvalidateCache((assetName, type) => { - IAssetInfo info = new AssetInfo(locale, assetName, type, this.MainContentManager.AssertAndNormaliseAssetName); + IAssetInfo info = new AssetInfo(locale, assetName, type, this.MainContentManager.AssertAndNormalizeAssetName); return predicate(info); }, dispose); } diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs index fc558eb9..de39dbae 100644 --- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs @@ -64,7 +64,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// A name for the mod manager. Not guaranteed to be unique. /// The service provider to use to locate services. /// The root directory to search for content. - /// The current culture for which to localise content. + /// The current culture for which to localize content. /// The central coordinator which manages content managers. /// Encapsulates monitoring and logging. /// Simplifies access to private code. @@ -109,7 +109,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Whether to read/write the loaded asset to the asset cache. public abstract T Load(string assetName, LocalizedContentManager.LanguageCode language, bool useCache); - /// Load the base asset without localisation. + /// Load the base asset without localization. /// The type of asset to load. /// The asset path relative to the loader root directory, not including the .xnb extension. [Obsolete("This method is implemented for the base game and should not be used directly. To load an asset from the underlying content manager directly, use " + nameof(BaseContentManager.RawLoad) + " instead.")] @@ -121,19 +121,19 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Perform any cleanup needed when the locale changes. public virtual void OnLocaleChanged() { } - /// Normalise path separators in a file path. For asset keys, see instead. - /// The file path to normalise. + /// Normalize path separators in a file path. For asset keys, see instead. + /// The file path to normalize. [Pure] - public string NormalisePathSeparators(string path) + public string NormalizePathSeparators(string path) { - return this.Cache.NormalisePathSeparators(path); + return this.Cache.NormalizePathSeparators(path); } - /// Assert that the given key has a valid format and return a normalised form consistent with the underlying cache. + /// Assert that the given key has a valid format and return a normalized form consistent with the underlying cache. /// The asset key to check. /// The asset key is empty or contains invalid characters. [SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")] - public string AssertAndNormaliseAssetName(string assetName) + public string AssertAndNormalizeAssetName(string assetName) { // NOTE: the game checks for ContentLoadException to handle invalid keys, so avoid // throwing other types like ArgumentException here. @@ -142,7 +142,7 @@ namespace StardewModdingAPI.Framework.ContentManagers if (assetName.Intersect(Path.GetInvalidPathChars()).Any()) throw new SContentLoadException("The asset key or local path contains invalid characters."); - return this.Cache.NormaliseKey(assetName); + return this.Cache.NormalizeKey(assetName); } /**** @@ -165,8 +165,8 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The asset path relative to the loader root directory, not including the .xnb extension. public bool IsLoaded(string assetName) { - assetName = this.Cache.NormaliseKey(assetName); - return this.IsNormalisedKeyLoaded(assetName); + assetName = this.Cache.NormalizeKey(assetName); + return this.IsNormalizedKeyLoaded(assetName); } /// Get the cached asset keys. @@ -248,7 +248,7 @@ namespace StardewModdingAPI.Framework.ContentManagers *********/ /// Load an asset file directly from the underlying content manager. /// The type of asset to load. - /// The normalised asset key. + /// The normalized asset key. /// Whether to read/write the loaded asset to the asset cache. protected virtual T RawLoad(string assetName, bool useCache) { @@ -264,17 +264,17 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The language code for which to inject the asset. protected virtual void Inject(string assetName, T value, LanguageCode language) { - assetName = this.AssertAndNormaliseAssetName(assetName); + assetName = this.AssertAndNormalizeAssetName(assetName); this.Cache[assetName] = value; } /// Parse a cache key into its component parts. /// The input cache key. /// The original asset name. - /// The asset locale code (or null if not localised). + /// The asset locale code (or null if not localized). protected void ParseCacheKey(string cacheKey, out string assetName, out string localeCode) { - // handle localised key + // handle localized key if (!string.IsNullOrWhiteSpace(cacheKey)) { int lastSepIndex = cacheKey.LastIndexOf(".", StringComparison.InvariantCulture); @@ -296,8 +296,8 @@ namespace StardewModdingAPI.Framework.ContentManagers } /// Get whether an asset has already been loaded. - /// The normalised asset name. - protected abstract bool IsNormalisedKeyLoaded(string normalisedAssetName); + /// The normalized asset name. + protected abstract bool IsNormalizedKeyLoaded(string normalizedAssetName); /// Get the locale codes (like ja-JP) used in asset keys. private IDictionary GetKeyLocales() diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 488ec245..c64e9ba9 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -26,8 +26,8 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Interceptors which edit matching assets after they're loaded. private IDictionary> Editors => this.Coordinator.Editors; - /// A lookup which indicates whether the asset is localisable (i.e. the filename contains the locale), if previously loaded. - private readonly IDictionary IsLocalisableLookup; + /// A lookup which indicates whether the asset is localizable (i.e. the filename contains the locale), if previously loaded. + private readonly IDictionary IsLocalizableLookup; /// Whether the next load is the first for any game content manager. private static bool IsFirstLoad = true; @@ -43,7 +43,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// A name for the mod manager. Not guaranteed to be unique. /// The service provider to use to locate services. /// The root directory to search for content. - /// The current culture for which to localise content. + /// The current culture for which to localize content. /// The central coordinator which manages content managers. /// Encapsulates monitoring and logging. /// Simplifies access to private code. @@ -52,7 +52,7 @@ namespace StardewModdingAPI.Framework.ContentManagers public GameContentManager(string name, IServiceProvider serviceProvider, string rootDirectory, CultureInfo currentCulture, ContentCoordinator coordinator, IMonitor monitor, Reflector reflection, Action onDisposing, Action onLoadingFirstAsset) : base(name, serviceProvider, rootDirectory, currentCulture, coordinator, monitor, reflection, onDisposing, isNamespaced: false) { - this.IsLocalisableLookup = reflection.GetField>(this, "_localizedAsset").GetValue(); + this.IsLocalizableLookup = reflection.GetField>(this, "_localizedAsset").GetValue(); this.OnLoadingFirstAsset = onLoadingFirstAsset; } @@ -70,8 +70,8 @@ namespace StardewModdingAPI.Framework.ContentManagers this.OnLoadingFirstAsset(); } - // normalise asset name - assetName = this.AssertAndNormaliseAssetName(assetName); + // normalize asset name + assetName = this.AssertAndNormalizeAssetName(assetName); if (this.TryParseExplicitLanguageAssetKey(assetName, out string newAssetName, out LanguageCode newLanguage)) return this.Load(newAssetName, newLanguage, useCache); @@ -101,10 +101,10 @@ namespace StardewModdingAPI.Framework.ContentManagers data = this.AssetsBeingLoaded.Track(assetName, () => { string locale = this.GetLocale(language); - IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.AssertAndNormaliseAssetName); + IAssetInfo info = new AssetInfo(locale, assetName, typeof(T), this.AssertAndNormalizeAssetName); IAssetData asset = this.ApplyLoader(info) - ?? new AssetDataForObject(info, this.RawLoad(assetName, language, useCache), this.AssertAndNormaliseAssetName); + ?? new AssetDataForObject(info, this.RawLoad(assetName, language, useCache), this.AssertAndNormalizeAssetName); asset = this.ApplyEditors(info, asset); return (T)asset.Data; }); @@ -122,7 +122,7 @@ namespace StardewModdingAPI.Framework.ContentManagers // find assets for which a translatable version was loaded HashSet removeAssetNames = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach (string key in this.IsLocalisableLookup.Where(p => p.Value).Select(p => p.Key)) + foreach (string key in this.IsLocalizableLookup.Where(p => p.Value).Select(p => p.Key)) removeAssetNames.Add(this.TryParseExplicitLanguageAssetKey(key, out string assetName, out _) ? assetName : key); // invalidate translatable assets @@ -149,20 +149,20 @@ namespace StardewModdingAPI.Framework.ContentManagers ** Private methods *********/ /// Get whether an asset has already been loaded. - /// The normalised asset name. - protected override bool IsNormalisedKeyLoaded(string normalisedAssetName) + /// The normalized asset name. + protected override bool IsNormalizedKeyLoaded(string normalizedAssetName) { // default English - if (this.Language == LocalizedContentManager.LanguageCode.en || this.Coordinator.IsManagedAssetKey(normalisedAssetName)) - return this.Cache.ContainsKey(normalisedAssetName); + if (this.Language == LocalizedContentManager.LanguageCode.en || this.Coordinator.IsManagedAssetKey(normalizedAssetName)) + return this.Cache.ContainsKey(normalizedAssetName); // translated - string keyWithLocale = $"{normalisedAssetName}.{this.GetLocale(this.GetCurrentLanguage())}"; - if (this.IsLocalisableLookup.TryGetValue(keyWithLocale, out bool localisable)) + string keyWithLocale = $"{normalizedAssetName}.{this.GetLocale(this.GetCurrentLanguage())}"; + if (this.IsLocalizableLookup.TryGetValue(keyWithLocale, out bool localizable)) { - return localisable + return localizable ? this.Cache.ContainsKey(keyWithLocale) - : this.Cache.ContainsKey(normalisedAssetName); + : this.Cache.ContainsKey(normalizedAssetName); } // not loaded yet @@ -190,13 +190,13 @@ namespace StardewModdingAPI.Framework.ContentManagers string keyWithLocale = $"{assetName}.{this.GetLocale(language)}"; if (this.Cache.ContainsKey(keyWithLocale)) { - this.IsLocalisableLookup[assetName] = true; - this.IsLocalisableLookup[keyWithLocale] = true; + this.IsLocalizableLookup[assetName] = true; + this.IsLocalizableLookup[keyWithLocale] = true; } else if (this.Cache.ContainsKey(assetName)) { - this.IsLocalisableLookup[assetName] = false; - this.IsLocalisableLookup[keyWithLocale] = false; + this.IsLocalizableLookup[assetName] = false; + this.IsLocalizableLookup[keyWithLocale] = false; } else this.Monitor.Log($"Asset '{assetName}' could not be found in the cache immediately after injection.", LogLevel.Error); @@ -204,7 +204,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Load an asset file directly from the underlying content manager. /// The type of asset to load. - /// The normalised asset key. + /// The normalized asset key. /// The language code for which to load content. /// Whether to read/write the loaded asset to the asset cache. /// Derived from . @@ -214,19 +214,19 @@ namespace StardewModdingAPI.Framework.ContentManagers if (language != LocalizedContentManager.LanguageCode.en) { string translatedKey = $"{assetName}.{this.GetLocale(language)}"; - if (!this.IsLocalisableLookup.TryGetValue(translatedKey, out bool isTranslatable) || isTranslatable) + if (!this.IsLocalizableLookup.TryGetValue(translatedKey, out bool isTranslatable) || isTranslatable) { try { T obj = base.RawLoad(translatedKey, useCache); - this.IsLocalisableLookup[assetName] = true; - this.IsLocalisableLookup[translatedKey] = true; + this.IsLocalizableLookup[assetName] = true; + this.IsLocalizableLookup[translatedKey] = true; return obj; } catch (ContentLoadException) { - this.IsLocalisableLookup[assetName] = false; - this.IsLocalisableLookup[translatedKey] = false; + this.IsLocalizableLookup[assetName] = false; + this.IsLocalizableLookup[translatedKey] = false; } } } @@ -313,7 +313,7 @@ namespace StardewModdingAPI.Framework.ContentManagers } // return matched asset - return new AssetDataForObject(info, data, this.AssertAndNormaliseAssetName); + return new AssetDataForObject(info, data, this.AssertAndNormalizeAssetName); } /// Apply any to a loaded asset. @@ -322,7 +322,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The loaded asset. private IAssetData ApplyEditors(IAssetInfo info, IAssetData asset) { - IAssetData GetNewData(object data) => new AssetDataForObject(info, data, this.AssertAndNormaliseAssetName); + IAssetData GetNewData(object data) => new AssetDataForObject(info, data, this.AssertAndNormalizeAssetName); // edit asset foreach (var entry in this.GetInterceptors(this.Editors)) diff --git a/src/SMAPI/Framework/ContentManagers/IContentManager.cs b/src/SMAPI/Framework/ContentManagers/IContentManager.cs index 78211821..12c01352 100644 --- a/src/SMAPI/Framework/ContentManagers/IContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/IContentManager.cs @@ -39,15 +39,15 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Perform any cleanup needed when the locale changes. void OnLocaleChanged(); - /// Normalise path separators in a file path. For asset keys, see instead. - /// The file path to normalise. + /// Normalize path separators in a file path. For asset keys, see instead. + /// The file path to normalize. [Pure] - string NormalisePathSeparators(string path); + string NormalizePathSeparators(string path); - /// Assert that the given key has a valid format and return a normalised form consistent with the underlying cache. + /// Assert that the given key has a valid format and return a normalized form consistent with the underlying cache. /// The asset key to check. /// The asset key is empty or contains invalid characters. - string AssertAndNormaliseAssetName(string assetName); + string AssertAndNormalizeAssetName(string assetName); /// Get the current content locale. string GetLocale(); diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index 34cabefc..b88bd71e 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -7,7 +7,7 @@ using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; using xTile; @@ -41,7 +41,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The game content manager used for map tilesheets not provided by the mod. /// The service provider to use to locate services. /// The root directory to search for content. - /// The current culture for which to localise content. + /// The current culture for which to localize content. /// The central coordinator which manages content managers. /// Encapsulates monitoring and logging. /// Simplifies access to private code. @@ -78,7 +78,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// Whether to read/write the loaded asset to the asset cache. public override T Load(string assetName, LanguageCode language, bool useCache) { - assetName = this.AssertAndNormaliseAssetName(assetName); + assetName = this.AssertAndNormalizeAssetName(assetName); // disable caching // This is necessary to avoid assets being shared between content managers, which can @@ -91,7 +91,7 @@ namespace StardewModdingAPI.Framework.ContentManagers // disable language handling // Mod files don't support automatic translation logic, so this should never happen. if (language != this.DefaultLanguage) - throw new InvalidOperationException("Localised assets aren't supported by the mod content manager."); + throw new InvalidOperationException("Localized assets aren't supported by the mod content manager."); // resolve managed asset key { @@ -121,7 +121,7 @@ namespace StardewModdingAPI.Framework.ContentManagers T data = this.RawLoad(assetName, useCache: false); if (data is Map map) { - this.NormaliseTilesheetPaths(map); + this.NormalizeTilesheetPaths(map); this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); } return data; @@ -161,7 +161,7 @@ namespace StardewModdingAPI.Framework.ContentManagers // fetch & cache FormatManager formatManager = FormatManager.Instance; Map map = formatManager.LoadMap(file.FullName); - this.NormaliseTilesheetPaths(map); + this.NormalizeTilesheetPaths(map); this.FixCustomTilesheetPaths(map, relativeMapPath: assetName); return (T)(object)map; } @@ -199,10 +199,10 @@ namespace StardewModdingAPI.Framework.ContentManagers ** Private methods *********/ /// Get whether an asset has already been loaded. - /// The normalised asset name. - protected override bool IsNormalisedKeyLoaded(string normalisedAssetName) + /// The normalized asset name. + protected override bool IsNormalizedKeyLoaded(string normalizedAssetName) { - return this.Cache.ContainsKey(normalisedAssetName); + return this.Cache.ContainsKey(normalizedAssetName); } /// Get a file from the mod folder. @@ -245,12 +245,12 @@ namespace StardewModdingAPI.Framework.ContentManagers return texture; } - /// Normalise map tilesheet paths for the current platform. + /// Normalize map tilesheet paths for the current platform. /// The map whose tilesheets to fix. - private void NormaliseTilesheetPaths(Map map) + private void NormalizeTilesheetPaths(Map map) { foreach (TileSheet tilesheet in map.TileSheets) - tilesheet.ImageSource = this.NormalisePathSeparators(tilesheet.ImageSource); + tilesheet.ImageSource = this.NormalizePathSeparators(tilesheet.ImageSource); } /// Fix custom map tilesheet paths so they can be found by the content manager. @@ -258,7 +258,7 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The relative map path within the mod folder. /// A map tilesheet couldn't be resolved. /// - /// The game's logic for tilesheets in is a bit specialised. It boils + /// The game's logic for tilesheets in is a bit specialized. It boils /// down to this: /// * If the location is indoors or the desert, or the image source contains 'path' or 'object', it's loaded /// as-is relative to the Content folder. @@ -276,7 +276,7 @@ namespace StardewModdingAPI.Framework.ContentManagers // get map info if (!map.TileSheets.Any()) return; - relativeMapPath = this.AssertAndNormaliseAssetName(relativeMapPath); // Mono's Path.GetDirectoryName doesn't handle Windows dir separators + relativeMapPath = this.AssertAndNormalizeAssetName(relativeMapPath); // Mono's Path.GetDirectoryName doesn't handle Windows dir separators string relativeMapFolder = Path.GetDirectoryName(relativeMapPath) ?? ""; // folder path containing the map, relative to the mod folder bool isOutdoors = map.Properties.TryGetValue("Outdoors", out PropertyValue outdoorsProperty) && outdoorsProperty != null; diff --git a/src/SMAPI/Framework/ContentPack.cs b/src/SMAPI/Framework/ContentPack.cs index 829a7dc1..9c0bb9d1 100644 --- a/src/SMAPI/Framework/ContentPack.cs +++ b/src/SMAPI/Framework/ContentPack.cs @@ -2,7 +2,7 @@ using System; using System.IO; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; using xTile; @@ -63,14 +63,14 @@ namespace StardewModdingAPI.Framework /// Read a JSON file from the content pack folder. /// The model type. - /// The file path relative to the contnet directory. - /// Returns the deserialised model, or null if the file doesn't exist or is empty. + /// The file path relative to the content directory. + /// Returns the deserialized model, or null if the file doesn't exist or is empty. /// The is not relative or contains directory climbing (../). public TModel ReadJsonFile(string path) where TModel : class { this.AssertRelativePath(path, nameof(this.ReadJsonFile)); - path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path)); + path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path)); return this.JsonHelper.ReadJsonFileIfExists(path, out TModel model) ? model : null; @@ -85,7 +85,7 @@ namespace StardewModdingAPI.Framework { this.AssertRelativePath(path, nameof(this.WriteJsonFile)); - path = Path.Combine(this.DirectoryPath, PathUtilities.NormalisePathSeparators(path)); + path = Path.Combine(this.DirectoryPath, PathUtilities.NormalizePathSeparators(path)); this.JsonHelper.WriteJsonFile(path, data); } diff --git a/src/SMAPI/Framework/Events/EventManager.cs b/src/SMAPI/Framework/Events/EventManager.cs index 23879f1d..18b00f69 100644 --- a/src/SMAPI/Framework/Events/EventManager.cs +++ b/src/SMAPI/Framework/Events/EventManager.cs @@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.Events /// Raised after the game finishes writing data to the save file (except the initial save creation). public readonly ManagedEvent Saved; - /// Raised after the player loads a save slot and the world is initialised. + /// Raised after the player loads a save slot and the world is initialized. public readonly ManagedEvent SaveLoaded; /// Raised after the game begins a new day, including when loading a save. @@ -152,15 +152,15 @@ namespace StardewModdingAPI.Framework.Events public readonly ManagedEvent TerrainFeatureListChanged; /**** - ** Specialised + ** Specialized ****/ - /// Raised when the low-level stage in the game's loading process has changed. See notes on . + /// Raised when the low-level stage in the game's loading process has changed. See notes on . public readonly ManagedEvent LoadStageChanged; - /// Raised before the game performs its overall update tick (≈60 times per second). See notes on . + /// Raised before the game performs its overall update tick (≈60 times per second). See notes on . public readonly ManagedEvent UnvalidatedUpdateTicking; - /// Raised after the game performs its overall update tick (≈60 times per second). See notes on . + /// Raised after the game performs its overall update tick (≈60 times per second). See notes on . public readonly ManagedEvent UnvalidatedUpdateTicked; @@ -172,7 +172,7 @@ namespace StardewModdingAPI.Framework.Events /// The mod registry with which to identify mods. public EventManager(IMonitor monitor, ModRegistry modRegistry) { - // create shortcut initialisers + // create shortcut initializers ManagedEvent ManageEventOf(string typeName, string eventName) => new ManagedEvent($"{typeName}.{eventName}", monitor, modRegistry); // init events (new) @@ -223,9 +223,9 @@ namespace StardewModdingAPI.Framework.Events this.ObjectListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.ObjectListChanged)); this.TerrainFeatureListChanged = ManageEventOf(nameof(IModEvents.World), nameof(IWorldEvents.TerrainFeatureListChanged)); - this.LoadStageChanged = ManageEventOf(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.LoadStageChanged)); - this.UnvalidatedUpdateTicking = ManageEventOf(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicking)); - this.UnvalidatedUpdateTicked = ManageEventOf(nameof(IModEvents.Specialised), nameof(ISpecialisedEvents.UnvalidatedUpdateTicked)); + this.LoadStageChanged = ManageEventOf(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.LoadStageChanged)); + this.UnvalidatedUpdateTicking = ManageEventOf(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.UnvalidatedUpdateTicking)); + this.UnvalidatedUpdateTicked = ManageEventOf(nameof(IModEvents.Specialized), nameof(ISpecializedEvents.UnvalidatedUpdateTicked)); } } } diff --git a/src/SMAPI/Framework/Events/ModEvents.cs b/src/SMAPI/Framework/Events/ModEvents.cs index 8ad3936c..1d1c92c6 100644 --- a/src/SMAPI/Framework/Events/ModEvents.cs +++ b/src/SMAPI/Framework/Events/ModEvents.cs @@ -26,8 +26,8 @@ namespace StardewModdingAPI.Framework.Events /// Events raised when something changes in the world. public IWorldEvents World { get; } - /// Events serving specialised edge cases that shouldn't be used by most mods. - public ISpecialisedEvents Specialised { get; } + /// Events serving specialized edge cases that shouldn't be used by most mods. + public ISpecializedEvents Specialized { get; } /********* @@ -44,7 +44,7 @@ namespace StardewModdingAPI.Framework.Events this.Multiplayer = new ModMultiplayerEvents(mod, eventManager); this.Player = new ModPlayerEvents(mod, eventManager); this.World = new ModWorldEvents(mod, eventManager); - this.Specialised = new ModSpecialisedEvents(mod, eventManager); + this.Specialized = new ModSpecializedEvents(mod, eventManager); } } } diff --git a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs index 0177c22e..c15460fa 100644 --- a/src/SMAPI/Framework/Events/ModGameLoopEvents.cs +++ b/src/SMAPI/Framework/Events/ModGameLoopEvents.cs @@ -72,7 +72,7 @@ namespace StardewModdingAPI.Framework.Events remove => this.EventManager.Saved.Remove(value); } - /// Raised after the player loads a save slot and the world is initialised. + /// Raised after the player loads a save slot and the world is initialized. public event EventHandler SaveLoaded { add => this.EventManager.SaveLoaded.Add(value); diff --git a/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs b/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs index 7c3e9dee..9388bdb2 100644 --- a/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs +++ b/src/SMAPI/Framework/Events/ModSpecialisedEvents.cs @@ -3,8 +3,8 @@ using StardewModdingAPI.Events; namespace StardewModdingAPI.Framework.Events { - /// Events serving specialised edge cases that shouldn't be used by most mods. - internal class ModSpecialisedEvents : ModEventsBase, ISpecialisedEvents + /// Events serving specialized edge cases that shouldn't be used by most mods. + internal class ModSpecializedEvents : ModEventsBase, ISpecializedEvents { /********* ** Accessors @@ -37,7 +37,7 @@ namespace StardewModdingAPI.Framework.Events /// Construct an instance. /// The mod which uses this instance. /// The underlying event manager. - internal ModSpecialisedEvents(IModMetadata mod, EventManager eventManager) + internal ModSpecializedEvents(IModMetadata mod, EventManager eventManager) : base(mod, eventManager) { } } } diff --git a/src/SMAPI/Framework/GameVersion.cs b/src/SMAPI/Framework/GameVersion.cs index 261de374..b9ef12c8 100644 --- a/src/SMAPI/Framework/GameVersion.cs +++ b/src/SMAPI/Framework/GameVersion.cs @@ -18,7 +18,7 @@ namespace StardewModdingAPI.Framework ["1.04"] = "1.0.4", ["1.05"] = "1.0.5", ["1.051"] = "1.0.6-prerelease1", // not a very good mapping, but good enough for SMAPI's purposes. - ["1.051b"] = "1.0.6-prelease2", + ["1.051b"] = "1.0.6-prerelease2", ["1.06"] = "1.0.6", ["1.07"] = "1.0.7", ["1.07a"] = "1.0.8-prerelease1", diff --git a/src/SMAPI/Framework/InternalExtensions.cs b/src/SMAPI/Framework/InternalExtensions.cs index f52bfe2b..c3155b1c 100644 --- a/src/SMAPI/Framework/InternalExtensions.cs +++ b/src/SMAPI/Framework/InternalExtensions.cs @@ -55,7 +55,7 @@ namespace StardewModdingAPI.Framework ** Exceptions ****/ /// Get a string representation of an exception suitable for writing to the error log. - /// The error to summarise. + /// The error to summarize. public static string GetLogSummary(this Exception exception) { switch (exception) diff --git a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs index 15b164b1..043ae376 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentHelper.cs @@ -87,7 +87,7 @@ namespace StardewModdingAPI.Framework.ModHelpers { try { - this.AssertAndNormaliseAssetName(key); + this.AssertAndNormalizeAssetName(key); switch (source) { case ContentSource.GameContent: @@ -106,12 +106,12 @@ namespace StardewModdingAPI.Framework.ModHelpers } } - /// Normalise an asset name so it's consistent with those generated by the game. This is mainly useful for string comparisons like on generated asset names, and isn't necessary when passing asset names into other content helper methods. + /// Normalize an asset name so it's consistent with those generated by the game. This is mainly useful for string comparisons like on generated asset names, and isn't necessary when passing asset names into other content helper methods. /// The asset key. [Pure] - public string NormaliseAssetName(string assetName) + public string NormalizeAssetName(string assetName) { - return this.ModContentManager.AssertAndNormaliseAssetName(assetName); + return this.ModContentManager.AssertAndNormalizeAssetName(assetName); } /// Get the underlying key in the game's content cache for an asset. This can be used to load custom map tilesheets, but should be avoided when you can use the content API instead. This does not validate whether the asset exists. @@ -123,7 +123,7 @@ namespace StardewModdingAPI.Framework.ModHelpers switch (source) { case ContentSource.GameContent: - return this.GameContentManager.AssertAndNormaliseAssetName(key); + return this.GameContentManager.AssertAndNormalizeAssetName(key); case ContentSource.ModFolder: return this.ModContentManager.GetInternalAssetKey(key); @@ -170,9 +170,9 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The asset key to check. /// The asset key is empty or contains invalid characters. [SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")] - private void AssertAndNormaliseAssetName(string key) + private void AssertAndNormalizeAssetName(string key) { - this.ModContentManager.AssertAndNormaliseAssetName(key); + this.ModContentManager.AssertAndNormalizeAssetName(key); if (Path.IsPathRooted(key)) throw new ArgumentException("The asset key must not be an absolute path."); } diff --git a/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs index 34f24d65..acdd82a0 100644 --- a/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.IO; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization.Models; namespace StardewModdingAPI.Framework.ModHelpers { @@ -38,7 +38,7 @@ namespace StardewModdingAPI.Framework.ModHelpers return this.ContentPacks.Value; } - /// Create a temporary content pack to read files from a directory, using randomised manifest fields. This will generate fake manifest data; any manifest.json in the directory will be ignored. Temporary content packs will not appear in the SMAPI log and update checks will not be performed. + /// Create a temporary content pack to read files from a directory, using randomized manifest fields. This will generate fake manifest data; any manifest.json in the directory will be ignored. Temporary content packs will not appear in the SMAPI log and update checks will not be performed. /// The absolute directory path containing the content pack files. public IContentPack CreateFake(string directoryPath) { diff --git a/src/SMAPI/Framework/ModHelpers/DataHelper.cs b/src/SMAPI/Framework/ModHelpers/DataHelper.cs index 3b5c1752..cc08c42b 100644 --- a/src/SMAPI/Framework/ModHelpers/DataHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/DataHelper.cs @@ -1,7 +1,7 @@ using System; using System.IO; using Newtonsoft.Json; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; @@ -40,14 +40,14 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Read data from a JSON file in the mod's folder. /// The model type. This should be a plain class that has public properties for the data you want. The properties can be complex types. /// The file path relative to the mod folder. - /// Returns the deserialised model, or null if the file doesn't exist or is empty. + /// Returns the deserialized model, or null if the file doesn't exist or is empty. /// The is not relative or contains directory climbing (../). public TModel ReadJsonFile(string path) where TModel : class { if (!PathUtilities.IsSafeRelativePath(path)) throw new InvalidOperationException($"You must call {nameof(IModHelper.Data)}.{nameof(this.ReadJsonFile)} with a relative path."); - path = Path.Combine(this.ModFolderPath, PathUtilities.NormalisePathSeparators(path)); + path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePathSeparators(path)); return this.JsonHelper.ReadJsonFileIfExists(path, out TModel data) ? data : null; @@ -63,7 +63,7 @@ namespace StardewModdingAPI.Framework.ModHelpers if (!PathUtilities.IsSafeRelativePath(path)) throw new InvalidOperationException($"You must call {nameof(IMod.Helper)}.{nameof(IModHelper.Data)}.{nameof(this.WriteJsonFile)} with a relative path (without directory climbing)."); - path = Path.Combine(this.ModFolderPath, PathUtilities.NormalisePathSeparators(path)); + path = Path.Combine(this.ModFolderPath, PathUtilities.NormalizePathSeparators(path)); this.JsonHelper.WriteJsonFile(path, data); } @@ -83,7 +83,7 @@ namespace StardewModdingAPI.Framework.ModHelpers 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.)"); return Game1.CustomData.TryGetValue(this.GetSaveFileKey(key), out string value) - ? this.JsonHelper.Deserialise(value) + ? this.JsonHelper.Deserialize(value) : null; } @@ -101,7 +101,7 @@ namespace StardewModdingAPI.Framework.ModHelpers string internalKey = this.GetSaveFileKey(key); if (data != null) - Game1.CustomData[internalKey] = this.JsonHelper.Serialise(data, Formatting.None); + Game1.CustomData[internalKey] = this.JsonHelper.Serialize(data, Formatting.None); else Game1.CustomData.Remove(internalKey); } diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index 86e8eb28..25401e23 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -2,7 +2,7 @@ using System; using System.IO; using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Input; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; namespace StardewModdingAPI.Framework.ModHelpers { @@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.ModHelpers if (!Directory.Exists(modDirectory)) throw new InvalidOperationException("The specified mod directory does not exist."); - // initialise + // initialize this.DirectoryPath = modDirectory; this.Content = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper)); this.ContentPacks = contentPackHelper ?? throw new ArgumentNullException(nameof(contentPackHelper)); diff --git a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs index 8330e078..24bed3bb 100644 --- a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs @@ -75,9 +75,9 @@ namespace StardewModdingAPI.Framework.ModHelpers public TInterface GetApi(string uniqueID) where TInterface : class { // validate - if (!this.Registry.AreAllModsInitialised) + if (!this.Registry.AreAllModsInitialized) { - this.Monitor.Log("Tried to access a mod-provided API before all mods were initialised.", LogLevel.Error); + this.Monitor.Log("Tried to access a mod-provided API before all mods were initialized.", LogLevel.Error); return null; } if (!typeof(TInterface).IsInterface) diff --git a/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs b/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs index 0ce72a9e..86c327ed 100644 --- a/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ReflectionHelper.cs @@ -5,7 +5,7 @@ using StardewModdingAPI.Framework.Reflection; namespace StardewModdingAPI.Framework.ModHelpers { /// Provides helper methods for accessing private game code. - /// This implementation searches up the type hierarchy, and caches the reflected fields and methods with a sliding expiry (to optimise performance without unnecessary memory usage). + /// This implementation searches up the type hierarchy, and caches the reflected fields and methods with a sliding expiry (to optimize performance without unnecessary memory usage). internal class ReflectionHelper : BaseHelper, IReflectionHelper { /********* diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 8dfacc33..7670eb3a 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -317,7 +317,7 @@ namespace StardewModdingAPI.Framework.ModLoading } /// Process the result from an instruction handler. - /// The mod being analysed. + /// The mod being analyzed. /// The instruction handler. /// The result returned by the handler. /// The messages already logged for the current mod. @@ -341,9 +341,9 @@ namespace StardewModdingAPI.Framework.ModLoading mod.SetWarning(ModWarning.PatchesGame); break; - case InstructionHandleResult.DetectedSaveSerialiser: - this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected possible save serialiser change ({handler.NounPhrase}) in assembly {filename}."); - mod.SetWarning(ModWarning.ChangesSaveSerialiser); + case InstructionHandleResult.DetectedSaveSerializer: + this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected possible save serializer change ({handler.NounPhrase}) in assembly {filename}."); + mod.SetWarning(ModWarning.ChangesSaveSerializer); break; case InstructionHandleResult.DetectedUnvalidatedUpdateTick: @@ -370,7 +370,7 @@ namespace StardewModdingAPI.Framework.ModLoading break; default: - throw new NotSupportedException($"Unrecognised instruction handler result '{result}'."); + throw new NotSupportedException($"Unrecognized instruction handler result '{result}'."); } } diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs index 79045241..701b15f2 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs @@ -73,7 +73,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Finders ** Protected methods *********/ /// Get whether a CIL instruction matches. - /// The method deifnition. + /// The method definition. protected bool IsMatch(MethodDefinition method) { if (this.IsMatch(method.ReturnType)) diff --git a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs index 6592760e..d93b603d 100644 --- a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs +++ b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs @@ -18,12 +18,12 @@ namespace StardewModdingAPI.Framework.ModLoading DetectedGamePatch, /// The instruction is compatible, but affects the save serializer in a way that may make saves unloadable without the mod. - DetectedSaveSerialiser, + DetectedSaveSerializer, /// The instruction is compatible, but uses the dynamic keyword which won't work on Linux/Mac. DetectedDynamic, - /// The instruction is compatible, but references or which may impact stability. + /// The instruction is compatible, but references or which may impact stability. DetectedUnvalidatedUpdateTick, /// The instruction accesses the filesystem directly. diff --git a/src/SMAPI/Framework/ModLoading/ModDependencyStatus.cs b/src/SMAPI/Framework/ModLoading/ModDependencyStatus.cs index 0774b487..dd855d2f 100644 --- a/src/SMAPI/Framework/ModLoading/ModDependencyStatus.cs +++ b/src/SMAPI/Framework/ModLoading/ModDependencyStatus.cs @@ -1,4 +1,4 @@ -namespace StardewModdingAPI.Framework.ModLoading +namespace StardewModdingAPI.Framework.ModLoading { /// The status of a given mod in the dependency-sorting algorithm. internal enum ModDependencyStatus @@ -6,7 +6,7 @@ /// The mod hasn't been visited yet. Queued, - /// The mod is currently being analysed as part of a dependency chain. + /// The mod is currently being analyzed as part of a dependency chain. Checking, /// The mod has already been sorted. diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 20941a5f..5ea21710 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -5,7 +5,7 @@ using System.Linq; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Framework.ModScanning; -using StardewModdingAPI.Toolkit.Serialisation.Models; +using StardewModdingAPI.Toolkit.Serialization.Models; using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Framework.ModLoading @@ -143,11 +143,11 @@ namespace StardewModdingAPI.Framework.ModLoading continue; } - // invalid capitalisation + // invalid capitalization string actualFilename = new DirectoryInfo(mod.DirectoryPath).GetFiles(mod.Manifest.EntryDll).FirstOrDefault()?.Name; if (actualFilename != mod.Manifest.EntryDll) { - 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."); + mod.SetStatus(ModMetadataStatus.Failed, $"its {nameof(IManifest.EntryDll)} value '{mod.Manifest.EntryDll}' doesn't match the actual file capitalization '{actualFilename}'. The capitalization must match for crossplatform compatibility."); continue; } } @@ -216,7 +216,7 @@ namespace StardewModdingAPI.Framework.ModLoading /// Handles access to SMAPI's internal mod metadata list. public IEnumerable ProcessDependencies(IEnumerable mods, ModDatabase modDatabase) { - // initialise metadata + // initialize metadata mods = mods.ToArray(); var sortedMods = new Stack(); var states = mods.ToDictionary(mod => mod, mod => ModDependencyStatus.Queued); diff --git a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs index f7497789..a4ac54e2 100644 --- a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs +++ b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs @@ -54,7 +54,7 @@ namespace StardewModdingAPI.Framework.ModLoading { bool HeuristicallyEquals(string typeNameA, string typeNameB, IDictionary tokenMap) { - // analyse type names + // analyze type names bool hasTokensA = typeNameA.Contains("!"); bool hasTokensB = typeNameB.Contains("!"); bool isTokenA = hasTokensA && typeNameA[0] == '!'; diff --git a/src/SMAPI/Framework/ModRegistry.cs b/src/SMAPI/Framework/ModRegistry.cs index 5be33cb4..ef389337 100644 --- a/src/SMAPI/Framework/ModRegistry.cs +++ b/src/SMAPI/Framework/ModRegistry.cs @@ -21,8 +21,8 @@ namespace StardewModdingAPI.Framework /// Whether all mod assemblies have been loaded. public bool AreAllModsLoaded { get; set; } - /// Whether all mods have been initialised and their method called. - public bool AreAllModsInitialised { get; set; } + /// Whether all mods have been initialized and their method called. + public bool AreAllModsInitialized { get; set; } /********* @@ -62,7 +62,7 @@ namespace StardewModdingAPI.Framework /// Returns the matching mod's metadata, or null if not found. public IModMetadata Get(string uniqueID) { - // normalise search ID + // normalize search ID if (string.IsNullOrWhiteSpace(uniqueID)) return null; uniqueID = uniqueID.Trim(); diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs index 3771f114..1fa55a9e 100644 --- a/src/SMAPI/Framework/Monitor.cs +++ b/src/SMAPI/Framework/Monitor.cs @@ -58,7 +58,7 @@ namespace StardewModdingAPI.Framework if (string.IsNullOrWhiteSpace(source)) throw new ArgumentException("The log source cannot be empty."); - // initialise + // initialize this.Source = source; this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null."); this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme); diff --git a/src/SMAPI/Framework/Networking/MessageType.cs b/src/SMAPI/Framework/Networking/MessageType.cs index bd9acfa9..4e1388ca 100644 --- a/src/SMAPI/Framework/Networking/MessageType.cs +++ b/src/SMAPI/Framework/Networking/MessageType.cs @@ -2,7 +2,7 @@ using StardewValley; namespace StardewModdingAPI.Framework.Networking { - /// Network message types recognised by SMAPI and Stardew Valley. + /// Network message types recognized by SMAPI and Stardew Valley. internal enum MessageType : byte { /********* diff --git a/src/SMAPI/Framework/Reflection/Reflector.cs b/src/SMAPI/Framework/Reflection/Reflector.cs index ed1a4381..d4904878 100644 --- a/src/SMAPI/Framework/Reflection/Reflector.cs +++ b/src/SMAPI/Framework/Reflection/Reflector.cs @@ -6,7 +6,7 @@ using System.Runtime.Caching; namespace StardewModdingAPI.Framework.Reflection { /// Provides helper methods for accessing inaccessible code. - /// This implementation searches up the type hierarchy, and caches the reflected fields and methods with a sliding expiry (to optimise performance without unnecessary memory usage). + /// This implementation searches up the type hierarchy, and caches the reflected fields and methods with a sliding expiry (to optimize performance without unnecessary memory usage). internal class Reflector { /********* diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 0aae3b84..c5dede01 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -24,13 +24,13 @@ using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Framework.ModLoading; using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; -using StardewModdingAPI.Framework.Serialisation; +using StardewModdingAPI.Framework.Serialization; using StardewModdingAPI.Internal; using StardewModdingAPI.Patches; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; using StardewModdingAPI.Toolkit.Framework.ModData; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; using Object = StardewValley.Object; @@ -38,7 +38,7 @@ using ThreadState = System.Threading.ThreadState; namespace StardewModdingAPI.Framework { - /// The core class which initialises and manages SMAPI. + /// The core class which initializes and manages SMAPI. internal class SCore : IDisposable { /********* @@ -56,7 +56,7 @@ namespace StardewModdingAPI.Framework /// The core logger and monitor on behalf of the game. private readonly Monitor MonitorForGame; - /// Tracks whether the game should exit immediately and any pending initialisation should be cancelled. + /// Tracks whether the game should exit immediately and any pending initialization should be cancelled. private readonly CancellationTokenSource CancellationToken = new CancellationTokenSource(); /// Simplifies access to private game code. @@ -72,7 +72,7 @@ namespace StardewModdingAPI.Framework private ContentCoordinator ContentCore => this.GameInstance.ContentCore; /// Tracks the installed mods. - /// This is initialised after the game starts. + /// This is initialized after the game starts. private readonly ModRegistry ModRegistry = new ModRegistry(); /// Manages SMAPI events for mods. @@ -120,7 +120,7 @@ namespace StardewModdingAPI.Framework ** Accessors *********/ /// Manages deprecation warnings. - /// This is initialised after the game starts. This is accessed directly because it's not part of the normal class model. + /// This is initialized after the game starts. This is accessed directly because it's not part of the normal class model. internal static DeprecationManager DeprecationManager { get; private set; } @@ -187,7 +187,7 @@ namespace StardewModdingAPI.Framework [HandleProcessCorruptedStateExceptions, SecurityCritical] // let try..catch handle corrupted state exceptions public void RunInteractively() { - // initialise SMAPI + // initialize SMAPI try { JsonConverter[] converters = { @@ -205,14 +205,14 @@ namespace StardewModdingAPI.Framework #endif AppDomain.CurrentDomain.UnhandledException += (sender, e) => this.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error); - // add more leniant assembly resolvers + // add more lenient assembly resolvers AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => AssemblyLoader.ResolveAssembly(e.Name); // hook locale event LocalizedContentManager.OnLanguageChange += locale => this.OnLocaleChanged(); // override game - SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper, this.InitialiseBeforeFirstAssetLoaded); + SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper, this.InitializeBeforeFirstAssetLoaded); this.GameInstance = new SGame( monitor: this.Monitor, monitorForGame: this.MonitorForGame, @@ -221,7 +221,7 @@ namespace StardewModdingAPI.Framework jsonHelper: this.Toolkit.JsonHelper, modRegistry: this.ModRegistry, deprecationManager: SCore.DeprecationManager, - onGameInitialised: this.InitialiseAfterGameStart, + onGameInitialized: this.InitializeAfterGameStart, onGameExiting: this.Dispose, cancellationToken: this.CancellationToken, logNetworkTraffic: this.Settings.LogNetworkTraffic @@ -262,7 +262,7 @@ namespace StardewModdingAPI.Framework } catch (Exception ex) { - this.Monitor.Log($"SMAPI failed to initialise: {ex.GetLogSummary()}", LogLevel.Error); + this.Monitor.Log($"SMAPI failed to initialize: {ex.GetLogSummary()}", LogLevel.Error); this.PressAnyKeyToExit(); return; } @@ -377,12 +377,12 @@ namespace StardewModdingAPI.Framework /********* ** Private methods *********/ - /// Initialise mods before the first game asset is loaded. At this point the core content managers are loaded (so mods can load their own assets), but the game is mostly uninitialised. - private void InitialiseBeforeFirstAssetLoaded() + /// Initialize mods before the first game asset is loaded. At this point the core content managers are loaded (so mods can load their own assets), but the game is mostly uninitialized. + private void InitializeBeforeFirstAssetLoaded() { if (this.CancellationToken.IsCancellationRequested) { - this.Monitor.Log("SMAPI shutting down: aborting initialisation.", LogLevel.Warn); + this.Monitor.Log("SMAPI shutting down: aborting initialization.", LogLevel.Warn); return; } @@ -432,8 +432,8 @@ namespace StardewModdingAPI.Framework Console.Title = $"SMAPI {Constants.ApiVersion} - running Stardew Valley {Constants.GameVersion} with {modsLoaded} mods"; } - /// Initialise SMAPI and mods after the game starts. - private void InitialiseAfterGameStart() + /// Initialize SMAPI and mods after the game starts. + private void InitializeAfterGameStart() { // validate XNB integrity if (!this.ValidateContentIntegrity()) @@ -696,7 +696,7 @@ namespace StardewModdingAPI.Framework /// Get whether a given version should be offered to the user as an update. /// The current semantic version. /// The target semantic version. - /// Whether the user enabled the beta channel and should be offered pre-release updates. + /// Whether the user enabled the beta channel and should be offered prerelease updates. private bool IsValidUpdate(ISemanticVersion currentVersion, ISemanticVersion newVersion, bool useBetaChannel) { return @@ -716,7 +716,7 @@ namespace StardewModdingAPI.Framework } catch (Exception ex) { - // note: this happens before this.Monitor is initialised + // note: this happens before this.Monitor is initialized Console.WriteLine($"Couldn't create a path: {path}\n\n{ex.GetLogSummary()}"); } } @@ -795,10 +795,10 @@ namespace StardewModdingAPI.Framework // log mod warnings this.LogModWarnings(loaded, skippedMods); - // initialise translations + // initialize translations this.ReloadTranslations(loaded); - // initialise loaded non-content-pack mods + // initialize loaded non-content-pack mods foreach (IModMetadata metadata in loadedMods) { // add interceptors @@ -847,7 +847,7 @@ namespace StardewModdingAPI.Framework } // invalidate cache entries when needed - // (These listeners are registered after Entry to avoid repeatedly reloading assets as mods initialise.) + // (These listeners are registered after Entry to avoid repeatedly reloading assets as mods initialize.) foreach (IModMetadata metadata in loadedMods) { if (metadata.Mod.Helper.Content is ContentHelper helper) @@ -881,7 +881,7 @@ namespace StardewModdingAPI.Framework } // unlock mod integrations - this.ModRegistry.AreAllModsInitialised = true; + this.ModRegistry.AreAllModsInitialized = true; } /// Load a given mod. @@ -924,7 +924,7 @@ namespace StardewModdingAPI.Framework } // validate dependencies - // Although dependences are validated before mods are loaded, a dependency may have failed to load. + // Although dependencies are validated before mods are loaded, a dependency may have failed to load. if (mod.Manifest.Dependencies?.Any() == true) { foreach (IManifestDependency dependency in mod.Manifest.Dependencies.Where(p => p.IsRequired)) @@ -988,7 +988,7 @@ namespace StardewModdingAPI.Framework return false; } - // initialise mod + // initialize mod try { // get mod instance @@ -1045,7 +1045,7 @@ namespace StardewModdingAPI.Framework } catch (Exception ex) { - errorReasonPhrase = $"initialisation failed:\n{ex.GetLogSummary()}"; + errorReasonPhrase = $"initialization failed:\n{ex.GetLogSummary()}"; return false; } } @@ -1120,8 +1120,8 @@ namespace StardewModdingAPI.Framework "These mods have broken code, but you configured SMAPI to load them anyway. This may cause bugs,", "errors, or crashes in-game." ); - LogWarningGroup(ModWarning.ChangesSaveSerialiser, LogLevel.Warn, "Changed save serialiser", - "These mods change the save serialiser. They may corrupt your save files, or make them unusable if", + LogWarningGroup(ModWarning.ChangesSaveSerializer, LogLevel.Warn, "Changed save serializer", + "These mods change the save serializer. They may corrupt your save files, or make them unusable if", "you uninstall these mods." ); if (this.Settings.ParanoidWarnings) @@ -1285,7 +1285,7 @@ namespace StardewModdingAPI.Framework break; default: - throw new NotSupportedException($"Unrecognise core SMAPI command '{name}'."); + throw new NotSupportedException($"Unrecognized core SMAPI command '{name}'."); } } diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 376368d6..e6d91fc3 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -18,7 +18,7 @@ using StardewModdingAPI.Framework.Networking; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.StateTracking.Snapshots; using StardewModdingAPI.Framework.Utilities; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewValley; using StardewValley.BellsAndWhistles; using StardewValley.Events; @@ -60,7 +60,7 @@ namespace StardewModdingAPI.Framework private readonly Countdown UpdateCrashTimer = new Countdown(60); // 60 ticks = roughly one second /// The number of ticks until SMAPI should notify mods that the game has loaded. - /// Skipping a few frames ensures the game finishes initialising the world before mods try to change it. + /// Skipping a few frames ensures the game finishes initializing the world before mods try to change it. private readonly Countdown AfterLoadTimer = new Countdown(5); /// Whether the game is saving and SMAPI has already raised . @@ -72,8 +72,8 @@ namespace StardewModdingAPI.Framework /// A callback to invoke the first time *any* game content manager loads an asset. private readonly Action OnLoadingFirstAsset; - /// A callback to invoke after the game finishes initialising. - private readonly Action OnGameInitialised; + /// A callback to invoke after the game finishes initializing. + private readonly Action OnGameInitialized; /// A callback to invoke when the game exits. private readonly Action OnGameExiting; @@ -93,8 +93,8 @@ namespace StardewModdingAPI.Framework /// A snapshot of the current state. private WatcherSnapshot WatcherSnapshot = new WatcherSnapshot(); - /// Whether post-game-startup initialisation has been performed. - private bool IsInitialised; + /// Whether post-game-startup initialization has been performed. + private bool IsInitialized; /// Whether the next content manager requested by the game will be for . private bool NextContentManagerIsMain; @@ -103,7 +103,7 @@ namespace StardewModdingAPI.Framework /********* ** Accessors *********/ - /// Static state to use while is initialising, which happens before the constructor runs. + /// Static state to use while is initializing, which happens before the constructor runs. internal static SGameConstructorHack ConstructorHack { get; set; } /// The number of update ticks which have already executed. This is similar to , but incremented more consistently for every tick. @@ -137,18 +137,18 @@ namespace StardewModdingAPI.Framework /// Encapsulates SMAPI's JSON file parsing. /// Tracks the installed mods. /// Manages deprecation warnings. - /// A callback to invoke after the game finishes initialising. + /// A callback to invoke after the game finishes initializing. /// A callback to invoke when the game exits. /// Propagates notification that SMAPI should exit. /// Whether to log network traffic. - internal SGame(Monitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialised, Action onGameExiting, CancellationTokenSource cancellationToken, bool logNetworkTraffic) + internal SGame(Monitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialized, Action onGameExiting, CancellationTokenSource cancellationToken, bool logNetworkTraffic) { this.OnLoadingFirstAsset = SGame.ConstructorHack.OnLoadingFirstAsset; SGame.ConstructorHack = null; // check expectations if (this.ContentCore == null) - throw new InvalidOperationException($"The game didn't initialise its first content manager before SMAPI's {nameof(SGame)} constructor. This indicates an incompatible lifecycle change."); + throw new InvalidOperationException($"The game didn't initialize its first content manager before SMAPI's {nameof(SGame)} constructor. This indicates an incompatible lifecycle change."); // init XNA Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef; @@ -160,7 +160,7 @@ namespace StardewModdingAPI.Framework this.ModRegistry = modRegistry; this.Reflection = reflection; this.DeprecationManager = deprecationManager; - this.OnGameInitialised = onGameInitialised; + this.OnGameInitialized = onGameInitialized; this.OnGameExiting = onGameExiting; Game1.input = new SInputState(); Game1.multiplayer = new SMultiplayer(monitor, eventManager, jsonHelper, modRegistry, reflection, this.OnModMessageReceived, logNetworkTraffic); @@ -171,8 +171,8 @@ namespace StardewModdingAPI.Framework Game1.locations = new ObservableCollection(); } - /// Initialise just before the game's first update tick. - private void InitialiseAfterGameStarted() + /// Initialize just before the game's first update tick. + private void InitializeAfterGameStarted() { // set initial state this.Input.TrueUpdate(); @@ -181,7 +181,7 @@ namespace StardewModdingAPI.Framework this.Watchers = new WatcherCore(this.Input); // raise callback - this.OnGameInitialised(); + this.OnGameInitialized(); } /// Perform cleanup logic when the game exits. @@ -238,8 +238,8 @@ namespace StardewModdingAPI.Framework /// The root directory to search for content. protected override LocalizedContentManager CreateContentManager(IServiceProvider serviceProvider, string rootDirectory) { - // Game1._temporaryContent initialising from SGame constructor - // NOTE: this method is called before the SGame constructor runs. Don't depend on anything being initialised at this point. + // Game1._temporaryContent initializing from SGame constructor + // NOTE: this method is called before the SGame constructor runs. Don't depend on anything being initialized at this point. if (this.ContentCore == null) { this.ContentCore = new ContentCoordinator(serviceProvider, rootDirectory, Thread.CurrentThread.CurrentUICulture, SGame.ConstructorHack.Monitor, SGame.ConstructorHack.Reflection, SGame.ConstructorHack.JsonHelper, this.OnLoadingFirstAsset ?? SGame.ConstructorHack?.OnLoadingFirstAsset); @@ -247,7 +247,7 @@ namespace StardewModdingAPI.Framework return this.ContentCore.CreateGameContentManager("Game1._temporaryContent"); } - // Game1.content initialising from LoadContent + // Game1.content initializing from LoadContent if (this.NextContentManagerIsMain) { this.NextContentManagerIsMain = false; @@ -269,12 +269,12 @@ namespace StardewModdingAPI.Framework this.DeprecationManager.PrintQueued(); /********* - ** First-tick initialisation + ** First-tick initialization *********/ - if (!this.IsInitialised) + if (!this.IsInitialized) { - this.IsInitialised = true; - this.InitialiseAfterGameStarted(); + this.IsInitialized = true; + this.InitializeAfterGameStarted(); } /********* @@ -302,7 +302,7 @@ namespace StardewModdingAPI.Framework bool saveParsed = false; if (Game1.currentLoader != null) { - this.Monitor.Log("Game loader synchronising...", LogLevel.Trace); + this.Monitor.Log("Game loader synchronizing...", LogLevel.Trace); while (Game1.currentLoader?.MoveNext() == true) { // raise load stage changed @@ -333,7 +333,7 @@ namespace StardewModdingAPI.Framework } if (Game1._newDayTask?.Status == TaskStatus.Created) { - this.Monitor.Log("New day task synchronising...", LogLevel.Trace); + this.Monitor.Log("New day task synchronizing...", LogLevel.Trace); Game1._newDayTask.RunSynchronously(); this.Monitor.Log("New day task done.", LogLevel.Trace); } @@ -346,7 +346,7 @@ namespace StardewModdingAPI.Framework // Therefore we can just run Game1.Update here without raising any SMAPI events. There's // a small chance that the task will finish after we defer but before the game checks, // which means technically events should be raised, but the effects of missing one - // update tick are neglible and not worth the complications of bypassing Game1.Update. + // update tick are negligible and not worth the complications of bypassing Game1.Update. if (Game1._newDayTask != null || Game1.gameMode == Game1.loadingMode) { events.UnvalidatedUpdateTicking.RaiseEmpty(); @@ -436,7 +436,7 @@ namespace StardewModdingAPI.Framework } else if (Context.IsSaveLoaded && this.AfterLoadTimer.Current > 0 && Game1.currentLocation != null) { - if (Game1.dayOfMonth != 0) // wait until new-game intro finishes (world not fully initialised yet) + if (Game1.dayOfMonth != 0) // wait until new-game intro finishes (world not fully initialized yet) this.AfterLoadTimer.Decrement(); Context.IsWorldReady = this.AfterLoadTimer.Current == 0; } diff --git a/src/SMAPI/Framework/SGameConstructorHack.cs b/src/SMAPI/Framework/SGameConstructorHack.cs index c3d22197..f70dec03 100644 --- a/src/SMAPI/Framework/SGameConstructorHack.cs +++ b/src/SMAPI/Framework/SGameConstructorHack.cs @@ -1,11 +1,11 @@ using System; using StardewModdingAPI.Framework.Reflection; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewValley; namespace StardewModdingAPI.Framework { - /// The static state to use while is initialising, which happens before the constructor runs. + /// The static state to use while is initializing, which happens before the constructor runs. internal class SGameConstructorHack { /********* diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index 531c229e..e04205c8 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -9,7 +9,7 @@ using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Events; using StardewModdingAPI.Framework.Networking; using StardewModdingAPI.Framework.Reflection; -using StardewModdingAPI.Toolkit.Serialisation; +using StardewModdingAPI.Toolkit.Serialization; using StardewValley; using StardewValley.Network; using StardewValley.SDKs; @@ -94,8 +94,8 @@ namespace StardewModdingAPI.Framework this.HostPeer = null; } - /// Initialise a client before the game connects to a remote server. - /// The client to initialise. + /// Initialize a client before the game connects to a remote server. + /// The client to initialize. public override Client InitClient(Client client) { switch (client) @@ -118,8 +118,8 @@ namespace StardewModdingAPI.Framework } } - /// Initialise a server before the game connects to an incoming player. - /// The server to initialise. + /// Initialize a server before the game connects to an incoming player. + /// The server to initialize. public override Server InitServer(Server server) { switch (server) @@ -423,7 +423,7 @@ namespace StardewModdingAPI.Framework private RemoteContextModel ReadContext(BinaryReader reader) { string data = reader.ReadString(); - RemoteContextModel model = this.JsonHelper.Deserialise(data); + RemoteContextModel model = this.JsonHelper.Deserialize(data); return model.ApiVersion != null ? model : null; // no data available for unmodded players @@ -435,7 +435,7 @@ namespace StardewModdingAPI.Framework { // parse message string json = message.Reader.ReadString(); - ModMessageModel model = this.JsonHelper.Deserialise(json); + ModMessageModel model = this.JsonHelper.Deserialize(json); HashSet playerIDs = new HashSet(model.ToPlayerIDs ?? this.GetKnownPlayerIDs()); if (this.LogNetworkTraffic) this.Monitor.Log($"Received message: {json}.", LogLevel.Trace); @@ -454,7 +454,7 @@ namespace StardewModdingAPI.Framework { newModel.ToPlayerIDs = new[] { peer.PlayerID }; this.Monitor.VerboseLog($" Forwarding message to player {peer.PlayerID}."); - peer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, peer.PlayerID, this.JsonHelper.Serialise(newModel, Formatting.None))); + peer.SendMessage(new OutgoingMessage((byte)MessageType.ModMessage, peer.PlayerID, this.JsonHelper.Serialize(newModel, Formatting.None))); } } } @@ -488,7 +488,7 @@ namespace StardewModdingAPI.Framework .ToArray() }; - return new object[] { this.JsonHelper.Serialise(model, Formatting.None) }; + return new object[] { this.JsonHelper.Serialize(model, Formatting.None) }; } /// Get the fields to include in a context sync message sent to other players. @@ -514,7 +514,7 @@ namespace StardewModdingAPI.Framework .ToArray() }; - return new object[] { this.JsonHelper.Serialise(model, Formatting.None) }; + return new object[] { this.JsonHelper.Serialize(model, Formatting.None) }; } } } diff --git a/src/SMAPI/Framework/Serialisation/ColorConverter.cs b/src/SMAPI/Framework/Serialisation/ColorConverter.cs deleted file mode 100644 index c27065bf..00000000 --- a/src/SMAPI/Framework/Serialisation/ColorConverter.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using Microsoft.Xna.Framework; -using Newtonsoft.Json.Linq; -using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Converters; - -namespace StardewModdingAPI.Framework.Serialisation -{ - /// Handles deserialisation of for crossplatform compatibility. - /// - /// - Linux/Mac format: { "B": 76, "G": 51, "R": 25, "A": 102 } - /// - Windows format: "26, 51, 76, 102" - /// - internal class ColorConverter : SimpleReadOnlyConverter - { - /********* - ** Protected methods - *********/ - /// Read a JSON object. - /// The JSON object to read. - /// The path to the current JSON node. - protected override Color ReadObject(JObject obj, string path) - { - int r = obj.ValueIgnoreCase(nameof(Color.R)); - int g = obj.ValueIgnoreCase(nameof(Color.G)); - int b = obj.ValueIgnoreCase(nameof(Color.B)); - int a = obj.ValueIgnoreCase(nameof(Color.A)); - return new Color(r, g, b, a); - } - - /// Read a JSON string. - /// The JSON string value. - /// The path to the current JSON node. - protected override Color ReadString(string str, string path) - { - string[] parts = str.Split(','); - if (parts.Length != 4) - throw new SParseException($"Can't parse {typeof(Color).Name} from invalid value '{str}' (path: {path})."); - - int r = Convert.ToInt32(parts[0]); - int g = Convert.ToInt32(parts[1]); - int b = Convert.ToInt32(parts[2]); - int a = Convert.ToInt32(parts[3]); - return new Color(r, g, b, a); - } - } -} diff --git a/src/SMAPI/Framework/Serialisation/PointConverter.cs b/src/SMAPI/Framework/Serialisation/PointConverter.cs deleted file mode 100644 index fbc857d2..00000000 --- a/src/SMAPI/Framework/Serialisation/PointConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using Microsoft.Xna.Framework; -using Newtonsoft.Json.Linq; -using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Converters; - -namespace StardewModdingAPI.Framework.Serialisation -{ - /// Handles deserialisation of for crossplatform compatibility. - /// - /// - Linux/Mac format: { "X": 1, "Y": 2 } - /// - Windows format: "1, 2" - /// - internal class PointConverter : SimpleReadOnlyConverter - { - /********* - ** Protected methods - *********/ - /// Read a JSON object. - /// The JSON object to read. - /// The path to the current JSON node. - protected override Point ReadObject(JObject obj, string path) - { - int x = obj.ValueIgnoreCase(nameof(Point.X)); - int y = obj.ValueIgnoreCase(nameof(Point.Y)); - return new Point(x, y); - } - - /// Read a JSON string. - /// The JSON string value. - /// The path to the current JSON node. - protected override Point ReadString(string str, string path) - { - string[] parts = str.Split(','); - if (parts.Length != 2) - throw new SParseException($"Can't parse {typeof(Point).Name} from invalid value '{str}' (path: {path})."); - - int x = Convert.ToInt32(parts[0]); - int y = Convert.ToInt32(parts[1]); - return new Point(x, y); - } - } -} diff --git a/src/SMAPI/Framework/Serialisation/RectangleConverter.cs b/src/SMAPI/Framework/Serialisation/RectangleConverter.cs deleted file mode 100644 index 4f55cc32..00000000 --- a/src/SMAPI/Framework/Serialisation/RectangleConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Text.RegularExpressions; -using Microsoft.Xna.Framework; -using Newtonsoft.Json.Linq; -using StardewModdingAPI.Toolkit.Serialisation; -using StardewModdingAPI.Toolkit.Serialisation.Converters; - -namespace StardewModdingAPI.Framework.Serialisation -{ - /// Handles deserialisation of for crossplatform compatibility. - /// - /// - Linux/Mac format: { "X": 1, "Y": 2, "Width": 3, "Height": 4 } - /// - Windows format: "{X:1 Y:2 Width:3 Height:4}" - /// - internal class RectangleConverter : SimpleReadOnlyConverter - { - /********* - ** Protected methods - *********/ - /// Read a JSON object. - /// The JSON object to read. - /// The path to the current JSON node. - protected override Rectangle ReadObject(JObject obj, string path) - { - int x = obj.ValueIgnoreCase(nameof(Rectangle.X)); - int y = obj.ValueIgnoreCase(nameof(Rectangle.Y)); - int width = obj.ValueIgnoreCase(nameof(Rectangle.Width)); - int height = obj.ValueIgnoreCase(nameof(Rectangle.Height)); - return new Rectangle(x, y, width, height); - } - - /// Read a JSON string. - /// The JSON string value. - /// The path to the current JSON node. - protected override Rectangle ReadString(string str, string path) - { - if (string.IsNullOrWhiteSpace(str)) - return Rectangle.Empty; - - var match = Regex.Match(str, @"^\{X:(?\d+) Y:(?\d+) Width:(?\d+) Height:(?\d+)\}$", RegexOptions.IgnoreCase); - if (!match.Success) - throw new SParseException($"Can't parse {typeof(Rectangle).Name} from invalid value '{str}' (path: {path})."); - - int x = Convert.ToInt32(match.Groups["x"].Value); - int y = Convert.ToInt32(match.Groups["y"].Value); - int width = Convert.ToInt32(match.Groups["width"].Value); - int height = Convert.ToInt32(match.Groups["height"].Value); - - return new Rectangle(x, y, width, height); - } - } -} diff --git a/src/SMAPI/Framework/Serialization/ColorConverter.cs b/src/SMAPI/Framework/Serialization/ColorConverter.cs new file mode 100644 index 00000000..19979981 --- /dev/null +++ b/src/SMAPI/Framework/Serialization/ColorConverter.cs @@ -0,0 +1,47 @@ +using System; +using Microsoft.Xna.Framework; +using Newtonsoft.Json.Linq; +using StardewModdingAPI.Toolkit.Serialization; +using StardewModdingAPI.Toolkit.Serialization.Converters; + +namespace StardewModdingAPI.Framework.Serialization +{ + /// Handles deserialization of for crossplatform compatibility. + /// + /// - Linux/Mac format: { "B": 76, "G": 51, "R": 25, "A": 102 } + /// - Windows format: "26, 51, 76, 102" + /// + internal class ColorConverter : SimpleReadOnlyConverter + { + /********* + ** Protected methods + *********/ + /// Read a JSON object. + /// The JSON object to read. + /// The path to the current JSON node. + protected override Color ReadObject(JObject obj, string path) + { + int r = obj.ValueIgnoreCase(nameof(Color.R)); + int g = obj.ValueIgnoreCase(nameof(Color.G)); + int b = obj.ValueIgnoreCase(nameof(Color.B)); + int a = obj.ValueIgnoreCase(nameof(Color.A)); + return new Color(r, g, b, a); + } + + /// Read a JSON string. + /// The JSON string value. + /// The path to the current JSON node. + protected override Color ReadString(string str, string path) + { + string[] parts = str.Split(','); + if (parts.Length != 4) + throw new SParseException($"Can't parse {typeof(Color).Name} from invalid value '{str}' (path: {path})."); + + int r = Convert.ToInt32(parts[0]); + int g = Convert.ToInt32(parts[1]); + int b = Convert.ToInt32(parts[2]); + int a = Convert.ToInt32(parts[3]); + return new Color(r, g, b, a); + } + } +} diff --git a/src/SMAPI/Framework/Serialization/PointConverter.cs b/src/SMAPI/Framework/Serialization/PointConverter.cs new file mode 100644 index 00000000..8c2f3396 --- /dev/null +++ b/src/SMAPI/Framework/Serialization/PointConverter.cs @@ -0,0 +1,43 @@ +using System; +using Microsoft.Xna.Framework; +using Newtonsoft.Json.Linq; +using StardewModdingAPI.Toolkit.Serialization; +using StardewModdingAPI.Toolkit.Serialization.Converters; + +namespace StardewModdingAPI.Framework.Serialization +{ + /// Handles deserialization of for crossplatform compatibility. + /// + /// - Linux/Mac format: { "X": 1, "Y": 2 } + /// - Windows format: "1, 2" + /// + internal class PointConverter : SimpleReadOnlyConverter + { + /********* + ** Protected methods + *********/ + /// Read a JSON object. + /// The JSON object to read. + /// The path to the current JSON node. + protected override Point ReadObject(JObject obj, string path) + { + int x = obj.ValueIgnoreCase(nameof(Point.X)); + int y = obj.ValueIgnoreCase(nameof(Point.Y)); + return new Point(x, y); + } + + /// Read a JSON string. + /// The JSON string value. + /// The path to the current JSON node. + protected override Point ReadString(string str, string path) + { + string[] parts = str.Split(','); + if (parts.Length != 2) + throw new SParseException($"Can't parse {typeof(Point).Name} from invalid value '{str}' (path: {path})."); + + int x = Convert.ToInt32(parts[0]); + int y = Convert.ToInt32(parts[1]); + return new Point(x, y); + } + } +} diff --git a/src/SMAPI/Framework/Serialization/RectangleConverter.cs b/src/SMAPI/Framework/Serialization/RectangleConverter.cs new file mode 100644 index 00000000..fbb2e253 --- /dev/null +++ b/src/SMAPI/Framework/Serialization/RectangleConverter.cs @@ -0,0 +1,52 @@ +using System; +using System.Text.RegularExpressions; +using Microsoft.Xna.Framework; +using Newtonsoft.Json.Linq; +using StardewModdingAPI.Toolkit.Serialization; +using StardewModdingAPI.Toolkit.Serialization.Converters; + +namespace StardewModdingAPI.Framework.Serialization +{ + /// Handles deserialization of for crossplatform compatibility. + /// + /// - Linux/Mac format: { "X": 1, "Y": 2, "Width": 3, "Height": 4 } + /// - Windows format: "{X:1 Y:2 Width:3 Height:4}" + /// + internal class RectangleConverter : SimpleReadOnlyConverter + { + /********* + ** Protected methods + *********/ + /// Read a JSON object. + /// The JSON object to read. + /// The path to the current JSON node. + protected override Rectangle ReadObject(JObject obj, string path) + { + int x = obj.ValueIgnoreCase(nameof(Rectangle.X)); + int y = obj.ValueIgnoreCase(nameof(Rectangle.Y)); + int width = obj.ValueIgnoreCase(nameof(Rectangle.Width)); + int height = obj.ValueIgnoreCase(nameof(Rectangle.Height)); + return new Rectangle(x, y, width, height); + } + + /// Read a JSON string. + /// The JSON string value. + /// The path to the current JSON node. + protected override Rectangle ReadString(string str, string path) + { + if (string.IsNullOrWhiteSpace(str)) + return Rectangle.Empty; + + var match = Regex.Match(str, @"^\{X:(?\d+) Y:(?\d+) Width:(?\d+) Height:(?\d+)\}$", RegexOptions.IgnoreCase); + if (!match.Success) + throw new SParseException($"Can't parse {typeof(Rectangle).Name} from invalid value '{str}' (path: {path})."); + + int x = Convert.ToInt32(match.Groups["x"].Value); + int y = Convert.ToInt32(match.Groups["y"].Value); + int width = Convert.ToInt32(match.Groups["width"].Value); + int height = Convert.ToInt32(match.Groups["height"].Value); + + return new Rectangle(x, y, width, height); + } + } +} diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs index 6550f950..32ec8c7e 100644 --- a/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs +++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/ComparableListWatcher.cs @@ -53,7 +53,7 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers { this.AssertNotDisposed(); - // optimise for zero items + // optimize for zero items if (this.CurrentValues.Count == 0) { if (this.LastValues.Count > 0) diff --git a/src/SMAPI/IAssetInfo.cs b/src/SMAPI/IAssetInfo.cs index 5dd58e2e..6cdf01ee 100644 --- a/src/SMAPI/IAssetInfo.cs +++ b/src/SMAPI/IAssetInfo.cs @@ -8,10 +8,10 @@ namespace StardewModdingAPI /********* ** Accessors *********/ - /// The content's locale code, if the content is localised. + /// The content's locale code, if the content is localized. string Locale { get; } - /// The normalised asset name being read. The format may change between platforms; see to compare with a known path. + /// The normalized asset name being read. The format may change between platforms; see to compare with a known path. string AssetName { get; } /// The content data type. @@ -21,7 +21,7 @@ namespace StardewModdingAPI /********* ** Public methods *********/ - /// Get whether the asset name being loaded matches a given name after normalisation. + /// Get whether the asset name being loaded matches a given name after normalization. /// The expected asset path, relative to the game's content folder and without the .xnb extension or locale suffix (like 'Data\ObjectInformation'). bool AssetNameEquals(string path); } diff --git a/src/SMAPI/IContentHelper.cs b/src/SMAPI/IContentHelper.cs index 1b87183d..dd7eb758 100644 --- a/src/SMAPI/IContentHelper.cs +++ b/src/SMAPI/IContentHelper.cs @@ -38,10 +38,10 @@ namespace StardewModdingAPI /// The content asset couldn't be loaded (e.g. because it doesn't exist). T Load(string key, ContentSource source = ContentSource.ModFolder); - /// Normalise an asset name so it's consistent with those generated by the game. This is mainly useful for string comparisons like on generated asset names, and isn't necessary when passing asset names into other content helper methods. + /// Normalize an asset name so it's consistent with those generated by the game. This is mainly useful for string comparisons like on generated asset names, and isn't necessary when passing asset names into other content helper methods. /// The asset key. [Pure] - string NormaliseAssetName(string assetName); + string NormalizeAssetName(string assetName); /// Get the underlying key in the game's content cache for an asset. This can be used to load custom map tilesheets, but should be avoided when you can use the content API instead. This does not validate whether the asset exists. /// The asset key to fetch (if the is ), or the local path to a content file relative to the mod folder. diff --git a/src/SMAPI/IContentPack.cs b/src/SMAPI/IContentPack.cs index 7085c538..c0479eae 100644 --- a/src/SMAPI/IContentPack.cs +++ b/src/SMAPI/IContentPack.cs @@ -31,7 +31,7 @@ namespace StardewModdingAPI /// Read a JSON file from the content pack folder. /// The model type. This should be a plain class that has public properties for the data you want. The properties can be complex types. /// The file path relative to the content pack directory. - /// Returns the deserialised model, or null if the file doesn't exist or is empty. + /// Returns the deserialized model, or null if the file doesn't exist or is empty. /// The is not relative or contains directory climbing (../). TModel ReadJsonFile(string path) where TModel : class; diff --git a/src/SMAPI/IContentPackHelper.cs b/src/SMAPI/IContentPackHelper.cs index e4949f58..c48a4f86 100644 --- a/src/SMAPI/IContentPackHelper.cs +++ b/src/SMAPI/IContentPackHelper.cs @@ -11,7 +11,7 @@ namespace StardewModdingAPI /// Get all content packs loaded for this mod. IEnumerable GetOwned(); - /// Create a temporary content pack to read files from a directory, using randomised manifest fields. Temporary content packs will not appear in the SMAPI log and update checks will not be performed. + /// Create a temporary content pack to read files from a directory, using randomized manifest fields. Temporary content packs will not appear in the SMAPI log and update checks will not be performed. /// The absolute directory path containing the content pack files. IContentPack CreateFake(string directoryPath); diff --git a/src/SMAPI/IDataHelper.cs b/src/SMAPI/IDataHelper.cs index 6afdc529..252030bd 100644 --- a/src/SMAPI/IDataHelper.cs +++ b/src/SMAPI/IDataHelper.cs @@ -14,7 +14,7 @@ namespace StardewModdingAPI /// Read data from a JSON file in the mod's folder. /// The model type. This should be a plain class that has public properties for the data you want. The properties can be complex types. /// The file path relative to the mod folder. - /// Returns the deserialised model, or null if the file doesn't exist or is empty. + /// Returns the deserialized model, or null if the file doesn't exist or is empty. /// The is not relative or contains directory climbing (../). TModel ReadJsonFile(string path) where TModel : class; diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 3fbca04a..b72590fd 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -24,8 +24,8 @@ namespace StardewModdingAPI.Metadata /********* ** Fields *********/ - /// Normalises an asset key to match the cache key. - private readonly Func GetNormalisedPath; + /// Normalizes an asset key to match the cache key. + private readonly Func GetNormalizedPath; /// Simplifies access to private game code. private readonly Reflector Reflection; @@ -33,7 +33,7 @@ namespace StardewModdingAPI.Metadata /// Encapsulates monitoring and logging. private readonly IMonitor Monitor; - /// Optimised bucket categories for batch reloading assets. + /// Optimized bucket categories for batch reloading assets. private enum AssetBucket { /// NPC overworld sprites. @@ -50,13 +50,13 @@ namespace StardewModdingAPI.Metadata /********* ** Public methods *********/ - /// Initialise the core asset data. - /// Normalises an asset key to match the cache key. + /// Initialize the core asset data. + /// Normalizes an asset key to match the cache key. /// Simplifies access to private code. /// Encapsulates monitoring and logging. - public CoreAssetPropagator(Func getNormalisedPath, Reflector reflection, IMonitor monitor) + public CoreAssetPropagator(Func getNormalizedPath, Reflector reflection, IMonitor monitor) { - this.GetNormalisedPath = getNormalisedPath; + this.GetNormalizedPath = getNormalizedPath; this.Reflection = reflection; this.Monitor = monitor; } @@ -67,7 +67,7 @@ namespace StardewModdingAPI.Metadata /// Returns the number of reloaded assets. public int Propagate(LocalizedContentManager content, IDictionary assets) { - // group into optimised lists + // group into optimized lists var buckets = assets.GroupBy(p => { if (this.IsInFolder(p.Key, "Characters") || this.IsInFolder(p.Key, "Characters\\Monsters")) @@ -112,7 +112,7 @@ namespace StardewModdingAPI.Metadata /// Returns whether an asset was loaded. The return value may be true or false, or a non-null value for true. private bool PropagateOther(LocalizedContentManager content, string key, Type type) { - key = this.GetNormalisedPath(key); + key = this.GetNormalizedPath(key); /**** ** Special case: current map tilesheet @@ -123,7 +123,7 @@ namespace StardewModdingAPI.Metadata { foreach (TileSheet tilesheet in Game1.currentLocation.map.TileSheets) { - if (this.GetNormalisedPath(tilesheet.ImageSource) == key) + if (this.GetNormalizedPath(tilesheet.ImageSource) == key) Game1.mapDisplayDevice.LoadTileSheet(tilesheet); } } @@ -136,7 +136,7 @@ namespace StardewModdingAPI.Metadata bool anyChanged = false; foreach (GameLocation location in this.GetLocations()) { - if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalisedPath(location.mapPath.Value) == key) + if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalizedPath(location.mapPath.Value) == key) { // general updates location.reloadMap(); @@ -162,7 +162,7 @@ namespace StardewModdingAPI.Metadata ** Propagate by key ****/ Reflector reflection = this.Reflection; - switch (key.ToLower().Replace("/", "\\")) // normalised key so we can compare statically + switch (key.ToLower().Replace("/", "\\")) // normalized key so we can compare statically { /**** ** Animals @@ -584,7 +584,7 @@ namespace StardewModdingAPI.Metadata let locCritters = this.Reflection.GetField>(location, "critters").GetValue() where locCritters != null from Critter critter in locCritters - where this.GetNormalisedPath(critter.sprite.textureName) == key + where this.GetNormalizedPath(critter.sprite.textureName) == key select critter ) .ToArray(); @@ -664,7 +664,7 @@ namespace StardewModdingAPI.Metadata // get NPCs HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); NPC[] characters = this.GetCharacters() - .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalisedPath(npc.Sprite.textureName.Value))) + .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalizedPath(npc.Sprite.textureName.Value))) .ToArray(); if (!characters.Any()) return 0; @@ -692,7 +692,7 @@ namespace StardewModdingAPI.Metadata ( from npc in this.GetCharacters() where npc.isVillager() - let textureKey = this.GetNormalisedPath($"Portraits\\{this.getTextureName(npc)}") + let textureKey = this.GetNormalizedPath($"Portraits\\{this.getTextureName(npc)}") where lookup.Contains(textureKey) select new { npc, textureKey } ) @@ -852,17 +852,17 @@ namespace StardewModdingAPI.Metadata } } - /// Get whether a key starts with a substring after the substring is normalised. + /// Get whether a key starts with a substring after the substring is normalized. /// The key to check. - /// The substring to normalise and find. + /// The substring to normalize and find. private bool KeyStartsWith(string key, string rawSubstring) { - return key.StartsWith(this.GetNormalisedPath(rawSubstring), StringComparison.InvariantCultureIgnoreCase); + return key.StartsWith(this.GetNormalizedPath(rawSubstring), StringComparison.InvariantCultureIgnoreCase); } - /// Get whether a normalised asset key is in the given folder. - /// The normalised asset key (like Animals/cat). - /// The key folder (like Animals); doesn't need to be normalised. + /// Get whether a normalized asset key is in the given folder. + /// The normalized asset key (like Animals/cat). + /// The key folder (like Animals); doesn't need to be normalized. /// Whether to return true if the key is inside a subfolder of the . private bool IsInFolder(string key, string folder, bool allowSubfolders = false) { diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index 72410d41..95482708 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -48,11 +48,11 @@ namespace StardewModdingAPI.Metadata ****/ yield return new TypeFinder("Harmony.HarmonyInstance", InstructionHandleResult.DetectedGamePatch); yield return new TypeFinder("System.Runtime.CompilerServices.CallSite", InstructionHandleResult.DetectedDynamic); - 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 EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicked), InstructionHandleResult.DetectedUnvalidatedUpdateTick); - yield return new EventFinder(typeof(ISpecialisedEvents).FullName, nameof(ISpecialisedEvents.UnvalidatedUpdateTicking), InstructionHandleResult.DetectedUnvalidatedUpdateTick); + yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerializer); + yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.farmerSerializer), InstructionHandleResult.DetectedSaveSerializer); + yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerializer); + yield return new EventFinder(typeof(ISpecializedEvents).FullName, nameof(ISpecializedEvents.UnvalidatedUpdateTicked), InstructionHandleResult.DetectedUnvalidatedUpdateTick); + yield return new EventFinder(typeof(ISpecializedEvents).FullName, nameof(ISpecializedEvents.UnvalidatedUpdateTicking), InstructionHandleResult.DetectedUnvalidatedUpdateTick); /**** ** detect paranoid issues diff --git a/src/SMAPI/Mod.cs b/src/SMAPI/Mod.cs index 3a753afc..0e5be1c1 100644 --- a/src/SMAPI/Mod.cs +++ b/src/SMAPI/Mod.cs @@ -41,7 +41,7 @@ namespace StardewModdingAPI ** Private methods *********/ /// Release or reset unmanaged resources when the game exits. There's no guarantee this will be called on every exit. - /// Whether the instance is being disposed explicitly rather than finalised. If this is false, the instance shouldn't dispose other objects since they may already be finalised. + /// Whether the instance is being disposed explicitly rather than finalized. If this is false, the instance shouldn't dispose other objects since they may already be finalized. protected virtual void Dispose(bool disposing) { } /// Destruct the instance. diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index df7654cd..6c94a2af 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -39,7 +39,7 @@ namespace StardewModdingAPI } catch (Exception ex) { - Console.WriteLine($"SMAPI failed to initialise: {ex}"); + Console.WriteLine($"SMAPI failed to initialize: {ex}"); Program.PressAnyKeyToExit(true); } } @@ -108,7 +108,7 @@ namespace StardewModdingAPI } - /// Initialise SMAPI and launch the game. + /// Initialize SMAPI and launch the game. /// The command-line arguments. /// This method is separate from because that can't contain any references to assemblies loaded by (e.g. via ), or Mono will incorrectly show an assembly resolution error before assembly resolution is set up. private static void Start(string[] args) diff --git a/src/SMAPI/SemanticVersion.cs b/src/SMAPI/SemanticVersion.cs index b346cfdd..0db41673 100644 --- a/src/SMAPI/SemanticVersion.cs +++ b/src/SMAPI/SemanticVersion.cs @@ -61,13 +61,13 @@ namespace StardewModdingAPI this.Version = version; } - /// Whether this is a pre-release version. + /// Whether this is a prerelease version. public bool IsPrerelease() { return this.Version.IsPrerelease(); } - /// Get an integer indicating whether this version precedes (less than 0), supercedes (more than 0), or is equivalent to (0) the specified version. + /// Get an integer indicating whether this version precedes (less than 0), supersedes (more than 0), or is equivalent to (0) the specified version. /// The version to compare with this instance. /// The value is null. /// The implementation is defined by Semantic Version 2.0 (https://semver.org/). diff --git a/src/SMAPI/Translation.cs b/src/SMAPI/Translation.cs index abcdb336..e8698e2c 100644 --- a/src/SMAPI/Translation.cs +++ b/src/SMAPI/Translation.cs @@ -38,7 +38,7 @@ namespace StardewModdingAPI /********* ** Public methods *********/ - /// Construct an isntance. + /// Construct an instance. /// The name of the relevant mod for error messages. /// The locale for which the translation was fetched. /// The translation key. @@ -46,7 +46,7 @@ namespace StardewModdingAPI internal Translation(string modName, string locale, string key, string text) : this(modName, locale, key, text, string.Format(Translation.PlaceholderText, key)) { } - /// Construct an isntance. + /// Construct an instance. /// The name of the relevant mod for error messages. /// The locale for which the translation was fetched. /// The translation key. diff --git a/src/SMAPI/Utilities/SDate.cs b/src/SMAPI/Utilities/SDate.cs index 9ea4f370..0ab37aa0 100644 --- a/src/SMAPI/Utilities/SDate.cs +++ b/src/SMAPI/Utilities/SDate.cs @@ -197,7 +197,7 @@ namespace StardewModdingAPI.Utilities if (year < 1) throw new ArgumentException($"Invalid year '{year}', must be at least 1."); - // initialise + // initialize this.Day = day; this.Season = season; this.Year = year; @@ -256,12 +256,12 @@ namespace StardewModdingAPI.Utilities /// Get a season index. /// The season name. - /// The current season wasn't recognised. + /// The current season wasn't recognized. private int GetSeasonIndex(string season) { int index = Array.IndexOf(this.Seasons, season); if (index == -1) - throw new InvalidOperationException($"The season '{season}' wasn't recognised."); + throw new InvalidOperationException($"The season '{season}' wasn't recognized."); return index; } } -- cgit From 49b3dbb38f57fa8552d267cdb71edf46f4a7a0ed Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 9 Aug 2019 17:05:27 -0400 Subject: update for game draw changes (#638) --- src/SMAPI/Framework/SGame.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index e6d91fc3..06c2ffe3 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -26,6 +26,8 @@ using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Tools; using xTile.Dimensions; +using xTile.Layers; +using xTile.Tiles; namespace StardewModdingAPI.Framework { @@ -1069,7 +1071,8 @@ namespace StardewModdingAPI.Framework } } } - Game1.currentLocation.Map.GetLayer("Buildings").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, 4); + Layer layer = Game1.currentLocation.Map.GetLayer("Buildings"); + layer.Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, 4); Game1.mapDisplayDevice.EndScene(); Game1.spriteBatch.End(); Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); @@ -1115,6 +1118,16 @@ namespace StardewModdingAPI.Framework if (Game1.player.currentUpgrade != null && Game1.player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && Game1.currentLocation.Name.Equals("Farm")) Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), new Microsoft.Xna.Framework.Rectangle?(Game1.player.currentUpgrade.getSourceRectangle()), Color.White, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, (float)(((double)Game1.player.currentUpgrade.positionOfCarpenter.Y + 48.0) / 10000.0)); Game1.currentLocation.draw(Game1.spriteBatch); + foreach (Vector2 key in Game1.crabPotOverlayTiles.Keys) + { + Tile tile = layer.Tiles[(int)key.X, (int)key.Y]; + if (tile != null) + { + Vector2 local = Game1.GlobalToLocal(Game1.viewport, key * 64f); + Location location = new Location((int)local.X, (int)local.Y); + Game1.mapDisplayDevice.DrawTile(tile, location, (float)(((double)key.Y * 64.0 - 1.0) / 10000.0)); + } + } if (Game1.eventUp && Game1.currentLocation.currentEvent != null) { string messageToScreen = Game1.currentLocation.currentEvent.messageToScreen; @@ -1170,7 +1183,8 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64) - 2, (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607) + 4, 12), Color.Black); Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64), (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607), 8), color); } - if (Game1.isDebrisWeather && Game1.currentLocation.IsOutdoors && (!(bool)((NetFieldBase)Game1.currentLocation.ignoreDebrisWeather) && !Game1.currentLocation.Name.Equals("Desert")) && Game1.viewport.X > -10) + bool flag = Game1.viewport.X > -Game1.viewport.Width; + if (((!Game1.isDebrisWeather || !Game1.currentLocation.IsOutdoors || (bool)((NetFieldBase)Game1.currentLocation.ignoreDebrisWeather) ? 0 : (!Game1.currentLocation.Name.Equals("Desert") ? 1 : 0)) & (flag ? 1 : 0)) != 0) { foreach (WeatherDebris weatherDebris in Game1.debrisWeather) weatherDebris.draw(Game1.spriteBatch); -- cgit From 25e4aa14d865cdf9f3616cfb0fd981aaaf0e3535 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 9 Aug 2019 17:47:53 -0400 Subject: remove legacy AssemblyInfo and GlobalAssemblyInfo files, use consistent assembly names --- build/GlobalAssemblyInfo.cs | 5 ----- build/common.targets | 3 +++ docs/technical/smapi.md | 12 ++++++------ src/SMAPI.Installer/Properties/AssemblyInfo.cs | 4 ---- src/SMAPI.Installer/SMAPI.Installer.csproj | 8 ++------ .../SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 2 ++ src/SMAPI.ModBuildConfig.Analyzer/Properties/AssemblyInfo.cs | 4 ---- .../SMAPI.ModBuildConfig.Analyzer.csproj | 9 ++++----- src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs | 6 ------ src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj | 4 ++-- src/SMAPI.Mods.ConsoleCommands/Properties/AssemblyInfo.cs | 4 ---- .../SMAPI.Mods.ConsoleCommands.csproj | 9 +-------- src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs | 4 ---- src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj | 9 +-------- src/SMAPI.Tests/Core/ModResolverTests.cs | 4 +++- src/SMAPI.Tests/Core/TranslationTests.cs | 3 ++- src/SMAPI.Tests/Properties/AssemblyInfo.cs | 4 ---- src/SMAPI.Tests/SMAPI.Tests.csproj | 8 +------- src/SMAPI.Tests/Sample.cs | 2 +- src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs | 2 +- src/SMAPI.Tests/Utilities/SDateTests.cs | 2 +- src/SMAPI.Tests/Utilities/SemanticVersionTests.cs | 3 ++- src/SMAPI.Toolkit.CoreInterfaces/Properties/AssemblyInfo.cs | 4 ---- .../SMAPI.Toolkit.CoreInterfaces.csproj | 9 +++------ src/SMAPI.Toolkit/ModToolkit.cs | 3 +++ src/SMAPI.Toolkit/Properties/AssemblyInfo.cs | 7 ------- src/SMAPI.Toolkit/SMAPI.Toolkit.csproj | 8 +++----- src/SMAPI.Web/Properties/AssemblyInfo.cs | 4 ---- src/SMAPI.Web/SMAPI.Web.csproj | 8 +++----- src/SMAPI/Program.cs | 3 +++ src/SMAPI/Properties/AssemblyInfo.cs | 7 ------- src/SMAPI/SMAPI.csproj | 8 ++------ 32 files changed, 49 insertions(+), 123 deletions(-) delete mode 100644 build/GlobalAssemblyInfo.cs delete mode 100644 src/SMAPI.Installer/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.ModBuildConfig.Analyzer/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.Mods.ConsoleCommands/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.Tests/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.Toolkit.CoreInterfaces/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.Toolkit/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI.Web/Properties/AssemblyInfo.cs delete mode 100644 src/SMAPI/Properties/AssemblyInfo.cs (limited to 'src/SMAPI') diff --git a/build/GlobalAssemblyInfo.cs b/build/GlobalAssemblyInfo.cs deleted file mode 100644 index 0fa0d331..00000000 --- a/build/GlobalAssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyProduct("SMAPI")] -[assembly: AssemblyVersion("3.0.0")] -[assembly: AssemblyFileVersion("3.0.0")] diff --git a/build/common.targets b/build/common.targets index 59d5bfd2..a9bc9ebb 100644 --- a/build/common.targets +++ b/build/common.targets @@ -4,6 +4,9 @@ + 3.0.0 + SMAPI + $(AssemblySearchPaths);{GAC} $(DefineConstants);SMAPI_FOR_WINDOWS diff --git a/docs/technical/smapi.md b/docs/technical/smapi.md index a006ff1a..f6994ba3 100644 --- a/docs/technical/smapi.md +++ b/docs/technical/smapi.md @@ -50,7 +50,7 @@ argument | purpose ### Compile flags SMAPI uses a small number of conditional compilation constants, which you can set by editing the -`` element in `StardewModdingAPI.csproj`. Supported constants: +`` element in `SMAPI.csproj`. Supported constants: flag | purpose ---- | ------- @@ -71,17 +71,17 @@ your current OS automatically and load the correct references. Compile output wi ### Debugging a local build Rebuilding the solution in debug mode will copy the SMAPI files into your game folder. Starting -the `StardewModdingAPI` project with debugging from Visual Studio (on Mac or Windows) will launch -SMAPI with the debugger attached, so you can intercept errors and step through the code being -executed. This doesn't work in MonoDevelop on Linux, unfortunately. +the `SMAPI` project with debugging from Visual Studio (on Mac or Windows) will launch SMAPI with +the debugger attached, so you can intercept errors and step through the code being executed. This +doesn't work in MonoDevelop on Linux, unfortunately. ### Preparing a release To prepare a crossplatform SMAPI release, you'll need to compile it on two platforms. See [crossplatforming info](https://stardewvalleywiki.com/Modding:Modder_Guide/Test_and_Troubleshoot#Testing_on_all_platforms) on the wiki for the first-time setup. -1. Update the version number in `GlobalAssemblyInfo.cs` and `Constants::Version`. Make sure you use a - [semantic version](https://semver.org). Recommended format: +1. Update the version number in `.root/build/common.targets` and `Constants::Version`. Make sure + you use a [semantic version](https://semver.org). Recommended format: build type | format | example :--------- | :----------------------- | :------ diff --git a/src/SMAPI.Installer/Properties/AssemblyInfo.cs b/src/SMAPI.Installer/Properties/AssemblyInfo.cs deleted file mode 100644 index 9838e5a0..00000000 --- a/src/SMAPI.Installer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SMAPI.Installer")] -[assembly: AssemblyDescription("The SMAPI installer for players.")] diff --git a/src/SMAPI.Installer/SMAPI.Installer.csproj b/src/SMAPI.Installer/SMAPI.Installer.csproj index a2e115e6..3f01c8fe 100644 --- a/src/SMAPI.Installer/SMAPI.Installer.csproj +++ b/src/SMAPI.Installer/SMAPI.Installer.csproj @@ -1,10 +1,10 @@  - SMAPI.Installer SMAPI.Installer + StardewModdingAPI.Installer + The SMAPI installer for players. net45 - false latest Exe x86 @@ -12,10 +12,6 @@ false - - - - diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index 40ceba3c..681eb5c2 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -16,4 +16,6 @@ + + diff --git a/src/SMAPI.ModBuildConfig.Analyzer/Properties/AssemblyInfo.cs b/src/SMAPI.ModBuildConfig.Analyzer/Properties/AssemblyInfo.cs deleted file mode 100644 index 1cc41000..00000000 --- a/src/SMAPI.ModBuildConfig.Analyzer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SMAPI.ModBuildConfig.Analyzer")] -[assembly: AssemblyDescription("")] diff --git a/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj index d812e9c6..3659e25a 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj @@ -1,17 +1,16 @@  + SMAPI.ModBuildConfig.Analyzer + StardewModdingAPI.ModBuildConfig.Analyzer + 3.0.0 netstandard2.0 - false + latest false bin latest - - - - diff --git a/src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs b/src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs deleted file mode 100644 index 255ce509..00000000 --- a/src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SMAPI.ModBuildConfig")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyVersion("3.0.0")] -[assembly: AssemblyFileVersion("3.0.0")] diff --git a/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj index e13526f9..137a6c4a 100644 --- a/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj +++ b/src/SMAPI.ModBuildConfig/SMAPI.ModBuildConfig.csproj @@ -1,10 +1,10 @@  - SMAPI.ModBuildConfig SMAPI.ModBuildConfig + StardewModdingAPI.ModBuildConfig + 3.0.0 net45 - false latest x86 false diff --git a/src/SMAPI.Mods.ConsoleCommands/Properties/AssemblyInfo.cs b/src/SMAPI.Mods.ConsoleCommands/Properties/AssemblyInfo.cs deleted file mode 100644 index 86653141..00000000 --- a/src/SMAPI.Mods.ConsoleCommands/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SMAPI.Mods.ConsoleCommands")] -[assembly: AssemblyDescription("")] diff --git a/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj index 80e1986e..ce35bf73 100644 --- a/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj +++ b/src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj @@ -1,10 +1,9 @@  - SMAPI.Mods.ConsoleCommands ConsoleCommands + StardewModdingAPI.Mods.ConsoleCommands net45 - false latest $(SolutionDir)\..\bin\$(Configuration)\Mods\ConsoleCommands false @@ -62,12 +61,6 @@ - - - Properties\GlobalAssemblyInfo.cs - - - PreserveNewest diff --git a/src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs b/src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs deleted file mode 100644 index fc6b26fa..00000000 --- a/src/SMAPI.Mods.SaveBackup/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("StardewModdingAPI.Mods.SaveBackup")] -[assembly: AssemblyDescription("")] diff --git a/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj index d2e41e77..2d031408 100644 --- a/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj +++ b/src/SMAPI.Mods.SaveBackup/SMAPI.Mods.SaveBackup.csproj @@ -1,10 +1,9 @@  - SMAPI.Mods.SaveBackup SaveBackup + StardewModdingAPI.Mods.SaveBackup net45 - false latest $(SolutionDir)\..\bin\$(Configuration)\Mods\SaveBackup false @@ -24,12 +23,6 @@ - - - Properties\GlobalAssemblyInfo.cs - - - PreserveNewest diff --git a/src/SMAPI.Tests/Core/ModResolverTests.cs b/src/SMAPI.Tests/Core/ModResolverTests.cs index c1aa0212..a9c88c60 100644 --- a/src/SMAPI.Tests/Core/ModResolverTests.cs +++ b/src/SMAPI.Tests/Core/ModResolverTests.cs @@ -5,13 +5,15 @@ using System.Linq; using Moq; using Newtonsoft.Json; using NUnit.Framework; +using StardewModdingAPI; using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.ModLoading; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Serialization.Models; +using SemanticVersion = StardewModdingAPI.SemanticVersion; -namespace StardewModdingAPI.Tests.Core +namespace SMAPI.Tests.Core { /// Unit tests for . [TestFixture] diff --git a/src/SMAPI.Tests/Core/TranslationTests.cs b/src/SMAPI.Tests/Core/TranslationTests.cs index eea301ae..c098aca5 100644 --- a/src/SMAPI.Tests/Core/TranslationTests.cs +++ b/src/SMAPI.Tests/Core/TranslationTests.cs @@ -2,10 +2,11 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using StardewModdingAPI; using StardewModdingAPI.Framework.ModHelpers; using StardewValley; -namespace StardewModdingAPI.Tests.Core +namespace SMAPI.Tests.Core { /// Unit tests for and . [TestFixture] diff --git a/src/SMAPI.Tests/Properties/AssemblyInfo.cs b/src/SMAPI.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 8b21e8fe..00000000 --- a/src/SMAPI.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SMAPI.Tests")] -[assembly: AssemblyDescription("")] diff --git a/src/SMAPI.Tests/SMAPI.Tests.csproj b/src/SMAPI.Tests/SMAPI.Tests.csproj index 41e12d7d..a627b3c3 100644 --- a/src/SMAPI.Tests/SMAPI.Tests.csproj +++ b/src/SMAPI.Tests/SMAPI.Tests.csproj @@ -1,8 +1,8 @@  - SMAPI.Tests SMAPI.Tests + SMAPI.Tests net45 false latest @@ -28,12 +28,6 @@ - - - Properties\GlobalAssemblyInfo.cs - - - diff --git a/src/SMAPI.Tests/Sample.cs b/src/SMAPI.Tests/Sample.cs index 6cd27707..f4f0d88e 100644 --- a/src/SMAPI.Tests/Sample.cs +++ b/src/SMAPI.Tests/Sample.cs @@ -1,6 +1,6 @@ using System; -namespace StardewModdingAPI.Tests +namespace SMAPI.Tests { /// Provides sample values for unit testing. internal static class Sample diff --git a/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs b/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs index 3dc65ed5..55785bfa 100644 --- a/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs +++ b/src/SMAPI.Tests/Toolkit/PathUtilitiesTests.cs @@ -1,7 +1,7 @@ using NUnit.Framework; using StardewModdingAPI.Toolkit.Utilities; -namespace StardewModdingAPI.Tests.Toolkit +namespace SMAPI.Tests.Toolkit { /// Unit tests for . [TestFixture] diff --git a/src/SMAPI.Tests/Utilities/SDateTests.cs b/src/SMAPI.Tests/Utilities/SDateTests.cs index 642f11f6..d25a101a 100644 --- a/src/SMAPI.Tests/Utilities/SDateTests.cs +++ b/src/SMAPI.Tests/Utilities/SDateTests.cs @@ -6,7 +6,7 @@ using System.Text.RegularExpressions; using NUnit.Framework; using StardewModdingAPI.Utilities; -namespace StardewModdingAPI.Tests.Utilities +namespace SMAPI.Tests.Utilities { /// Unit tests for . [TestFixture] diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs index 8f64a5fb..8da64c27 100644 --- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs +++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs @@ -2,9 +2,10 @@ using System; using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using NUnit.Framework; +using StardewModdingAPI; using StardewModdingAPI.Framework; -namespace StardewModdingAPI.Tests.Utilities +namespace SMAPI.Tests.Utilities { /// Unit tests for . [TestFixture] diff --git a/src/SMAPI.Toolkit.CoreInterfaces/Properties/AssemblyInfo.cs b/src/SMAPI.Toolkit.CoreInterfaces/Properties/AssemblyInfo.cs deleted file mode 100644 index a29ba6cf..00000000 --- a/src/SMAPI.Toolkit.CoreInterfaces/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SMAPI.Toolkit.CoreInterfaces")] -[assembly: AssemblyDescription("Provides toolkit interfaces which are available to SMAPI mods.")] diff --git a/src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj b/src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj index 7d8fc998..a39ef3af 100644 --- a/src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj +++ b/src/SMAPI.Toolkit.CoreInterfaces/SMAPI.Toolkit.CoreInterfaces.csproj @@ -1,18 +1,15 @@  + SMAPI.Toolkit.CoreInterfaces + StardewModdingAPI + Provides toolkit interfaces which are available to SMAPI mods. net4.5;netstandard2.0 - SMAPI - false ..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces ..\..\bin\$(Configuration)\SMAPI.Toolkit.CoreInterfaces\$(TargetFramework)\SMAPI.Toolkit.CoreInterfaces.xml latest - - - - diff --git a/src/SMAPI.Toolkit/ModToolkit.cs b/src/SMAPI.Toolkit/ModToolkit.cs index 08fe0fed..80b14659 100644 --- a/src/SMAPI.Toolkit/ModToolkit.cs +++ b/src/SMAPI.Toolkit/ModToolkit.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Newtonsoft.Json; using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; @@ -10,6 +11,8 @@ using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Framework.ModScanning; using StardewModdingAPI.Toolkit.Serialization; +[assembly: InternalsVisibleTo("StardewModdingAPI")] +[assembly: InternalsVisibleTo("SMAPI.Web")] namespace StardewModdingAPI.Toolkit { /// A convenience wrapper for the various tools. diff --git a/src/SMAPI.Toolkit/Properties/AssemblyInfo.cs b/src/SMAPI.Toolkit/Properties/AssemblyInfo.cs deleted file mode 100644 index ec873f79..00000000 --- a/src/SMAPI.Toolkit/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -[assembly: AssemblyTitle("SMAPI.Toolkit")] -[assembly: AssemblyDescription("A library which encapsulates mod-handling logic for mod managers and tools. Not intended for use by mods.")] -[assembly: InternalsVisibleTo("StardewModdingAPI")] -[assembly: InternalsVisibleTo("SMAPI.Web")] diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj index 1cdde423..71b8fc55 100644 --- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj +++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj @@ -1,8 +1,10 @@  + SMAPI.Toolkit + StardewModdingAPI.Toolkit + A library which encapsulates mod-handling logic for mod managers and tools. Not intended for use by mods. net4.5;netstandard2.0 - false ..\..\bin\$(Configuration)\SMAPI.Toolkit ..\..\bin\$(Configuration)\SMAPI.Toolkit\$(TargetFramework)\SMAPI.Toolkit.xml latest @@ -10,10 +12,6 @@ StardewModdingAPI.Toolkit - - - - diff --git a/src/SMAPI.Web/Properties/AssemblyInfo.cs b/src/SMAPI.Web/Properties/AssemblyInfo.cs deleted file mode 100644 index 31e6fc30..00000000 --- a/src/SMAPI.Web/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SMAPI.Web")] -[assembly: AssemblyDescription("")] diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj index 98517818..316a6a28 100644 --- a/src/SMAPI.Web/SMAPI.Web.csproj +++ b/src/SMAPI.Web/SMAPI.Web.csproj @@ -1,9 +1,9 @@  + SMAPI.Web StardewModdingAPI.Web netcoreapp2.0 - false latest @@ -11,10 +11,6 @@ - - - - @@ -52,4 +48,6 @@ + + diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 6c94a2af..2d143439 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -3,12 +3,15 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; #if SMAPI_FOR_WINDOWS #endif using StardewModdingAPI.Framework; using StardewModdingAPI.Toolkit.Utilities; +[assembly: InternalsVisibleTo("SMAPI.Tests")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // Moq for unit testing namespace StardewModdingAPI { /// The main entry point for SMAPI, responsible for hooking into and launching the game. diff --git a/src/SMAPI/Properties/AssemblyInfo.cs b/src/SMAPI/Properties/AssemblyInfo.cs deleted file mode 100644 index 03843ea8..00000000 --- a/src/SMAPI/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -[assembly: AssemblyTitle("SMAPI")] -[assembly: AssemblyDescription("A modding API for Stardew Valley.")] -[assembly: InternalsVisibleTo("StardewModdingAPI.Tests")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // Moq for unit testing diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 0157e66a..f41ede29 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -1,10 +1,10 @@  - StardewModdingAPI StardewModdingAPI + StardewModdingAPI + The modding API for Stardew Valley. net45 - false latest x86 Exe @@ -91,10 +91,6 @@ - - - - PreserveNewest -- cgit From 192c54b71cf438768ac5f6c37ae9acd53bea9111 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 14 Aug 2019 13:26:32 -0400 Subject: update for game draw changes (#638) --- src/SMAPI/Framework/SGame.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 06c2ffe3..cb1b9be5 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -1096,6 +1096,7 @@ namespace StardewModdingAPI.Framework } foreach (Farmer farmerShadow in this._farmerShadows) { + float num1 = Math.Max(0.0001f, farmerShadow.getDrawLayer() + 0.00011f) - 0.0001f; if (!(bool)((NetFieldBase)farmerShadow.swimming) && !farmerShadow.isRidingHorse() && (Game1.currentLocation != null && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(farmerShadow.getTileLocation()))) { SpriteBatch spriteBatch = Game1.spriteBatch; @@ -1108,8 +1109,9 @@ namespace StardewModdingAPI.Framework bounds = Game1.shadowTexture.Bounds; double y = (double)bounds.Center.Y; Vector2 origin = new Vector2((float)x, (float)y); - double num = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); - spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, 0.0f, origin, (float)num, SpriteEffects.None, 0.0f); + double num2 = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); + double num3 = (double)num1; + spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, 0.0f, origin, (float)num2, SpriteEffects.None, (float)num3); } } } -- cgit From 1003116f7f95d149b350642db8da2464d9ed9954 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 18 Aug 2019 01:00:11 -0400 Subject: fix asset changes not affecting cached asset loads in a specific case --- docs/release-notes.md | 1 + src/SMAPI/Framework/ContentManagers/GameContentManager.cs | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 5f964cfd..01b48998 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -59,6 +59,7 @@ These changes have not been released yet. * Removed the `Monitor.ExitGameImmediately` method. * Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4). * Fixed issue where mod changes weren't tracked correctly for raising events in some cases. Events now reflect a frozen snapshot of the game state, and any mod changes are reflected in the next event tick. + * Fixed issue where, when a mod's `IAssetEditor` uses `asset.ReplaceWith` on a texture asset while playing in non-English, any changes from that point won't affect subsequent cached asset loads. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. ## 2.11.3 diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index c64e9ba9..0b563555 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -184,10 +184,20 @@ namespace StardewModdingAPI.Framework.ContentManagers return; } } + + // save to cache + // Note: even if the asset was loaded and cached right before this method was called, + // we need to fully re-inject it here for two reasons: + // 1. So we can look up an asset by its base or localized key (the game/XNA logic + // only caches by the most specific key). + // 2. Because a mod asset loader/editor may have changed the asset in a way that + // doesn't change the instance stored in the cache, e.g. using `asset.ReplaceWith`. + string keyWithLocale = $"{assetName}.{this.GetLocale(language)}"; base.Inject(assetName, value, language); + if (this.Cache.ContainsKey(keyWithLocale)) + base.Inject(keyWithLocale, value, language); // track whether the injected asset is translatable for is-loaded lookups - string keyWithLocale = $"{assetName}.{this.GetLocale(language)}"; if (this.Cache.ContainsKey(keyWithLocale)) { this.IsLocalizableLookup[assetName] = true; -- cgit From 7ca168269fc8cc76d900fba6c6d04d2b02287956 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 29 Aug 2019 13:45:21 -0400 Subject: log skipped loose files --- docs/release-notes.md | 6 +++--- src/SMAPI/Framework/SCore.cs | 8 +++++++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 352198e0..500f2427 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,9 +9,9 @@ These changes have not been released yet. * Improved performance. * Rewrote launch script on Linux to improve compatibility (thanks to kurumushi and toastal!). * Improved mod scanning: - * Now ignores metadata files/folders like `__MACOSX` and `__folder_managed_by_vortex`. - * Now ignores content files like `.txt` or `.png`, which avoids missing-manifest errors in some common cases. - * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods. + * Now ignores metadata files and folders (like `__MACOSX` and `__folder_managed_by_vortex`) and content files (like `.txt` or `.png`), which avoids missing-manifest errors in some common cases. + * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages. + * Added trace logs for skipped loose files so it's easier to troubleshoot player logs. * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. * Duplicate-mod errors now show the mod version in each folder. * Updated mod compatibility list. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index c5dede01..fde28852 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -25,7 +25,6 @@ using StardewModdingAPI.Framework.ModLoading; using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Serialization; -using StardewModdingAPI.Internal; using StardewModdingAPI.Patches; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; @@ -395,6 +394,13 @@ namespace StardewModdingAPI.Framework this.Monitor.Log("Loading mod metadata...", LogLevel.Trace); ModResolver resolver = new ModResolver(); + // log loose files + { + string[] looseFiles = new DirectoryInfo(this.ModsPath).GetFiles().Select(p => p.Name).ToArray(); + if (looseFiles.Any()) + this.Monitor.Log($" Ignored loose files: {string.Join(", ", looseFiles.OrderBy(p => p, StringComparer.InvariantCultureIgnoreCase))}", LogLevel.Trace); + } + // load manifests IModMetadata[] mods = resolver.ReadManifests(toolkit, this.ModsPath, modDatabase).ToArray(); -- cgit From 8cb190de080aad56372b1c63d8b4f977f3c81d01 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 31 Aug 2019 17:46:47 -0400 Subject: add Android detection --- docs/release-notes.md | 1 + src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs | 68 +++++++++++++++++++---- src/SMAPI/GamePlatform.cs | 3 + 3 files changed, 60 insertions(+), 12 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index a52b3e7f..7740cb1c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -52,6 +52,7 @@ These changes have not been released yet. * Added fields and methods: `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`. * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. * Added asset propagation for critter textures and `DayTimeMoneyBox` buttons. + * `Constants.TargetPlatform` now returns `Android` when playing on an Android device. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. * Trace logs for a broken mod now list all detected issues (instead of the first one). * Trace logs when loading mods are now more clear. diff --git a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs index 4f67c00e..6dce5da5 100644 --- a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs +++ b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; #if SMAPI_FOR_WINDOWS @@ -14,6 +15,9 @@ namespace StardewModdingAPI.Toolkit.Utilities /********* ** Fields *********/ + /// The cached platform. + private static Platform? CachedPlatform; + /// Get the OS name from the system uname command. /// The buffer to fill with the resulting string. [DllImport("libc")] @@ -26,19 +30,10 @@ namespace StardewModdingAPI.Toolkit.Utilities /// Detect the current OS. public static Platform DetectPlatform() { - switch (Environment.OSVersion.Platform) - { - case PlatformID.MacOSX: - return Platform.Mac; + if (EnvironmentUtility.CachedPlatform == null) + EnvironmentUtility.CachedPlatform = EnvironmentUtility.DetectPlatformImpl(); - case PlatformID.Unix: - return EnvironmentUtility.IsRunningMac() - ? Platform.Mac - : Platform.Linux; - - default: - return Platform.Windows; - } + return EnvironmentUtility.CachedPlatform.Value; } @@ -81,6 +76,55 @@ namespace StardewModdingAPI.Toolkit.Utilities /********* ** Private methods *********/ + /// Detect the current OS. + private static Platform DetectPlatformImpl() + { + switch (Environment.OSVersion.Platform) + { + case PlatformID.MacOSX: + return Platform.Mac; + + case PlatformID.Unix when EnvironmentUtility.IsRunningAndroid(): + return Platform.Android; + + case PlatformID.Unix when EnvironmentUtility.IsRunningMac(): + return Platform.Mac; + + case PlatformID.Unix: + return Platform.Linux; + + default: + return Platform.Windows; + } + } + + /// Detect whether the code is running on Android. + /// + /// This code is derived from https://stackoverflow.com/a/47521647/262123. It detects Android by calling the + /// getprop system command to check for an Android-specific property. + /// + private static bool IsRunningAndroid() + { + using (Process process = new Process()) + { + process.StartInfo.FileName = "getprop"; + process.StartInfo.Arguments = "ro.build.user"; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + try + { + process.Start(); + string output = process.StandardOutput.ReadToEnd(); + return !string.IsNullOrEmpty(output); + } + catch + { + return false; + } + } + } + /// Detect whether the code is running on Mac. /// /// This code is derived from the Mono project (see System.Windows.Forms/System.Windows.Forms/XplatUI.cs). It detects Mac by calling the diff --git a/src/SMAPI/GamePlatform.cs b/src/SMAPI/GamePlatform.cs index 174239e0..b64595e4 100644 --- a/src/SMAPI/GamePlatform.cs +++ b/src/SMAPI/GamePlatform.cs @@ -5,6 +5,9 @@ namespace StardewModdingAPI /// The game's platform version. public enum GamePlatform { + /// The Android version of the game. + Android = Platform.Android, + /// The Linux version of the game. Linux = Platform.Linux, -- cgit From 1db1a8fa2346c3aa77547c22b4d069fbc8b8ea60 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 31 Aug 2019 17:48:48 -0400 Subject: update SMAPI/game version map --- docs/release-notes.md | 3 ++- src/SMAPI/Constants.cs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 7740cb1c..0202015b 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -14,11 +14,12 @@ These changes have not been released yet. * Added trace logs for skipped loose files so it's easier to troubleshoot player logs. * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. * Duplicate-mod errors now show the mod version in each folder. - * Updated mod compatibility list. * Improved update checks: * Update checks are now faster in some cases. * Fixed error if a Nexus mod is marked as adult content. * Fixed error if the Chucklefish page for an update key doesn't exist. + * Updated mod compatibility list. + * Updated SMAPI/game version map. * Fixed mods needing to load custom `Map` assets before the game accesses them (SMAPI will now do so automatically). * Fixed Save Backup not pruning old backups if they're uncompressed. * Fixed issues when a farmhand reconnects before the game notices they're disconnected. diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 4e24477b..e3a6e6d5 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -111,6 +111,13 @@ namespace StardewModdingAPI { switch (version.ToString()) { + case "1.3.36": + return new SemanticVersion(2, 11, 2); + + case "1.3.32": + case "1.3.33": + return new SemanticVersion(2, 10, 2); + case "1.3.28": return new SemanticVersion(2, 7, 0); -- cgit From 2d6175fcd27d83f7f09e570252f9e45c44115b0a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 4 Sep 2019 18:57:07 -0400 Subject: add immutable collection watcher --- .../FieldWatchers/ImmutableCollectionWatcher.cs | 37 ++++++++++++++++++++++ .../StateTracking/FieldWatchers/WatcherFactory.cs | 35 +++++++++++++------- .../Framework/StateTracking/LocationTracker.cs | 5 +-- 3 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs new file mode 100644 index 00000000..30e6274f --- /dev/null +++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/ImmutableCollectionWatcher.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers +{ + /// A collection watcher which never changes. + /// The value type within the collection. + internal class ImmutableCollectionWatcher : BaseDisposableWatcher, ICollectionWatcher + { + /********* + ** Accessors + *********/ + /// A singleton collection watcher instance. + public static ImmutableCollectionWatcher Instance { get; } = new ImmutableCollectionWatcher(); + + /// Whether the collection changed since the last reset. + public bool IsChanged { get; } = false; + + /// The values added since the last reset. + public IEnumerable Added { get; } = new TValue[0]; + + /// The values removed since the last reset. + public IEnumerable Removed { get; } = new TValue[0]; + + + /********* + ** Public methods + *********/ + /// Update the current value if needed. + public void Update() { } + + /// Set the current value as the baseline. + public void Reset() { } + + /// Stop watching the field and release all references. + public override void Dispose() { } + } +} diff --git a/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs b/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs index 8301351e..314ff7f5 100644 --- a/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs +++ b/src/SMAPI/Framework/StateTracking/FieldWatchers/WatcherFactory.cs @@ -12,10 +12,13 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers /********* ** Public methods *********/ + /**** + ** Values + ****/ /// Get a watcher which compares values using their method. This method should only be used when won't work, since this doesn't validate whether they're comparable. /// The value type. /// Get the current value. - public static ComparableWatcher ForGenericEquality(Func getValue) where T : struct + public static IValueWatcher ForGenericEquality(Func getValue) where T : struct { return new ComparableWatcher(getValue, new GenericEqualsComparer()); } @@ -23,7 +26,7 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers /// Get a watcher for an value. /// The value type. /// Get the current value. - public static ComparableWatcher ForEquatable(Func getValue) where T : IEquatable + public static IValueWatcher ForEquatable(Func getValue) where T : IEquatable { return new ComparableWatcher(getValue, new EquatableComparer()); } @@ -31,15 +34,27 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers /// Get a watcher which detects when an object reference changes. /// The value type. /// Get the current value. - public static ComparableWatcher ForReference(Func getValue) + public static IValueWatcher ForReference(Func getValue) { return new ComparableWatcher(getValue, new ObjectReferenceComparer()); } + /// Get a watcher for a net collection. + /// The value type. + /// The net field instance type. + /// The net collection. + public static IValueWatcher ForNetValue(NetFieldBase field) where TSelf : NetFieldBase + { + return new NetValueWatcher(field); + } + + /**** + ** Collections + ****/ /// Get a watcher which detects when an object reference in a collection changes. /// The value type. /// The observable collection. - public static ComparableListWatcher ForReferenceList(ICollection collection) + public static ICollectionWatcher ForReferenceList(ICollection collection) { return new ComparableListWatcher(collection, new ObjectReferenceComparer()); } @@ -47,24 +62,22 @@ namespace StardewModdingAPI.Framework.StateTracking.FieldWatchers /// Get a watcher for an observable collection. /// The value type. /// The observable collection. - public static ObservableCollectionWatcher ForObservableCollection(ObservableCollection collection) + public static ICollectionWatcher ForObservableCollection(ObservableCollection collection) { return new ObservableCollectionWatcher(collection); } - /// Get a watcher for a net collection. + /// Get a watcher for a collection that never changes. /// The value type. - /// The net field instance type. - /// The net collection. - public static NetValueWatcher ForNetValue(NetFieldBase field) where TSelf : NetFieldBase + public static ICollectionWatcher ForImmutableCollection() { - return new NetValueWatcher(field); + return ImmutableCollectionWatcher.Instance; } /// Get a watcher for a net collection. /// The value type. /// The net collection. - public static NetCollectionWatcher ForNetCollection(NetCollection collection) where T : class, INetObject + public static ICollectionWatcher ForNetCollection(NetCollection collection) where T : class, INetObject { return new NetCollectionWatcher(collection); } diff --git a/src/SMAPI/Framework/StateTracking/LocationTracker.cs b/src/SMAPI/Framework/StateTracking/LocationTracker.cs index 2249e41b..1f479e12 100644 --- a/src/SMAPI/Framework/StateTracking/LocationTracker.cs +++ b/src/SMAPI/Framework/StateTracking/LocationTracker.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using Microsoft.Xna.Framework; using StardewModdingAPI.Framework.StateTracking.FieldWatchers; @@ -59,9 +58,7 @@ namespace StardewModdingAPI.Framework.StateTracking this.Location = location; // init watchers - this.BuildingsWatcher = location is BuildableGameLocation buildableLocation - ? WatcherFactory.ForNetCollection(buildableLocation.buildings) - : (ICollectionWatcher)WatcherFactory.ForObservableCollection(new ObservableCollection()); + this.BuildingsWatcher = location is BuildableGameLocation buildableLocation ? WatcherFactory.ForNetCollection(buildableLocation.buildings) : WatcherFactory.ForImmutableCollection(); this.DebrisWatcher = WatcherFactory.ForNetCollection(location.debris); this.LargeTerrainFeaturesWatcher = WatcherFactory.ForNetCollection(location.largeTerrainFeatures); this.NpcsWatcher = WatcherFactory.ForNetCollection(location.characters); -- cgit From 2f9884c47be16d476d5acbecd053b0754fa2bd59 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 5 Sep 2019 02:09:24 -0400 Subject: update packages --- docs/release-notes.md | 2 +- .../SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 2 +- src/SMAPI.Tests/SMAPI.Tests.csproj | 2 +- src/SMAPI.Toolkit/SMAPI.Toolkit.csproj | 2 +- src/SMAPI.Web/SMAPI.Web.csproj | 8 ++++---- src/SMAPI/SMAPI.csproj | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 0202015b..4009d234 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -62,7 +62,7 @@ These changes have not been released yet. * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalized for the OS automatically. * Removed all deprecated APIs. * Removed the `Monitor.ExitGameImmediately` method. - * Updated dependencies (including Json.NET 11.0.2 → 12.0.2, Mono.Cecil 0.10.1 → 0.10.4). + * Updated dependencies (including Json.NET 11.0.2 → 12.0.2 and Mono.Cecil 0.10.1 → 0.11). * Fixed issue where mod changes weren't tracked correctly for raising events in some cases. Events now reflect a frozen snapshot of the game state, and any mod changes are reflected in the next event tick. * Fixed issue where, when a mod's `IAssetEditor` uses `asset.ReplaceWith` on a texture asset while playing in non-English, any changes from that point won't affect subsequent cached asset loads. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index 681eb5c2..e7c3e3dc 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/SMAPI.Tests/SMAPI.Tests.csproj b/src/SMAPI.Tests/SMAPI.Tests.csproj index a627b3c3..84a05aee 100644 --- a/src/SMAPI.Tests/SMAPI.Tests.csproj +++ b/src/SMAPI.Tests/SMAPI.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj index 71b8fc55..a932c41b 100644 --- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj +++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj index f7b2dc24..c6ee7594 100644 --- a/src/SMAPI.Web/SMAPI.Web.csproj +++ b/src/SMAPI.Web/SMAPI.Web.csproj @@ -12,9 +12,9 @@ - - - + + + @@ -22,7 +22,7 @@ - + diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index f41ede29..7c7bfc71 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -18,7 +18,7 @@ - + -- cgit From dbd0b97c1790445e8ea187765a79ed22f9f0454b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 7 Sep 2019 06:10:23 -0400 Subject: simplify Data/NPCDispositions propagation with changes in SDV 1.4 (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index b72590fd..5911ba2c 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -632,27 +632,18 @@ namespace StardewModdingAPI.Metadata /// Returns whether any NPCs were affected. private bool ReloadNpcDispositions(LocalizedContentManager content, string key) { - IDictionary dispositions = content.Load>(key); + IDictionary data = content.Load>(key); + bool changed = false; foreach (NPC character in this.GetCharacters()) { - if (!character.isVillager() || !dispositions.ContainsKey(character.Name)) - continue; - - NPC clone = new NPC(null, character.Position, character.DefaultMap, character.FacingDirection, character.Name, null, character.Portrait, eventActor: false); - character.Age = clone.Age; - character.Manners = clone.Manners; - character.SocialAnxiety = clone.SocialAnxiety; - character.Optimism = clone.Optimism; - character.Gender = clone.Gender; - character.datable.Value = clone.datable.Value; - character.homeRegion = clone.homeRegion; - character.Birthday_Season = clone.Birthday_Season; - character.Birthday_Day = clone.Birthday_Day; - character.id = clone.id; - character.displayName = clone.displayName; + if (character.isVillager() && data.ContainsKey(character.Name)) + { + character.reloadData(); + changed = true; + } } - return true; + return changed; } /// Reload the sprites for matching NPCs. -- cgit From f5b46e8f3da3bb55ef1a116a8c24afa7fe2ec85b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 7 Sep 2019 06:11:27 -0400 Subject: add asset propagation for Data\FarmAnimals (#618) --- docs/release-notes.md | 2 +- src/SMAPI/Metadata/CoreAssetPropagator.cs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 4009d234..aab2edb3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -52,7 +52,7 @@ These changes have not been released yet. * Added support for content pack translations. * Added fields and methods: `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`. * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. - * Added asset propagation for critter textures and `DayTimeMoneyBox` buttons. + * Added asset propagation for `Data\FarmAnimals`, critter textures, and `DayTimeMoneyBox` buttons. * `Constants.TargetPlatform` now returns `Android` when playing on an Android device. * The installer now recognises custom game paths stored in `stardewvalley.targets`, if any. * Trace logs for a broken mod now list all detected issues (instead of the first one). diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 5911ba2c..66e6ed14 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -231,6 +231,9 @@ namespace StardewModdingAPI.Metadata CraftingRecipe.craftingRecipes = content.Load>(key); return true; + case "data\\farmanimals": // FarmAnimal constructor + return this.ReloadFarmAnimalData(); + case "data\\npcdispositions": // NPC constructor return this.ReloadNpcDispositions(content, key); @@ -599,6 +602,21 @@ namespace StardewModdingAPI.Metadata return critters.Length; } + /// Reload the data for matching farm animals. + /// Returns whether any farm animals were affected. + /// Derived from the constructor. + private bool ReloadFarmAnimalData() + { + bool changed = false; + foreach (FarmAnimal animal in this.GetFarmAnimals()) + { + animal.reloadData(); + changed = true; + } + + return changed; + } + /// Reload the sprites for a fence type. /// The asset key to reload. /// Returns whether any textures were reloaded. -- cgit From 4b3a593941bf9880404171c4bef9a3b3f60b6dca Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 7 Sep 2019 16:38:17 -0400 Subject: track texture asset keys, fix NPC portrait propagation --- docs/release-notes.md | 10 ++++---- .../ContentManagers/BaseContentManager.cs | 6 +++++ src/SMAPI/Metadata/CoreAssetPropagator.cs | 28 +++++++--------------- 3 files changed, 20 insertions(+), 24 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index fbd5df75..0f5547ff 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -18,7 +18,7 @@ For players: For modders: * **New event system.** - SMAPI 3.0 removes the deprecated static events in favor of the new `helper.Events` API. The event engine has been rewritten to make events more efficient, add events that weren't possible before, make existing events more useful, and make event usage and behavior more consistent. + SMAPI 3.0 removes the deprecated static events in favor of the new `helper.Events` API. The event engine has been rewritten to make events more efficient, add events that weren't possible before, make existing events more useful, and make event usage and behavior more consistent. When a mod makes changes in an event handler, those changes are now also reflected in the next event raise. * **Improved mod build package.** The [mod build package](https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig) has been improved to include the `assets` folder by default if present, support the new `.csproj` project format, enable mod `.pdb` files automatically (to provide line numbers in error messages), add optional Harmony support, and fix some bugs and edge cases. This also adds compatibility with SMAPI 3.0 and Stardew Valley 1.4, and drops support for older versions. @@ -30,7 +30,7 @@ For modders: SMAPI now automatically detects when it's running on Android, and updates the `Constants.TargetPlatform` for mods to use. * **Improved asset propagation.** - SMAPI now automatically propagates content changes for farm animal data, critter textures, and `DayTimeMoneyBox` buttons. + SMAPI now automatically propagates content changes for farm animal data, critter textures, and `DayTimeMoneyBox` buttons. It also sets the `Texture2D.Name` field to the loaded asset key for all image assets, so mods can check which asset a texture was loaded for. * **Breaking changes:** See _[migrate to SMAPI 3.0](https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0)_ for more info. @@ -91,16 +91,18 @@ For modders: * Added `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`. * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. * Added asset propagation for `Data\FarmAnimals`, critter textures, and `DayTimeMoneyBox` buttons. + * Added `Texture2D.Name` values set to the asset key. * `Constants.TargetPlatform` now returns `Android` when playing on an Android device. * Trace logs for a broken mod now list all detected issues (instead of the first one). * Trace logs when loading mods are now more clear. * Clarified update-check errors for mods with multiple update keys. - * Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted. - * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalized for the OS automatically. * Updated dependencies (including Json.NET 11.0.2 → 12.0.2 and Mono.Cecil 0.10.1 → 0.11). * Fixes: + * Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted. + * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalized for the OS automatically. * Fixed issue where mod changes weren't tracked correctly for raising events in some cases. Events now reflect a frozen snapshot of the game state, and any mod changes are reflected in the next event tick. * Fixed issue where, when a mod's `IAssetEditor` uses `asset.ReplaceWith` on a texture asset while playing in non-English, any changes from that point won't affect subsequent cached asset loads. + * Fixed asset propagation for NPC portraits resetting any unique portraits (e.g. Maru's hospital portrait) to the default. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. ## 2.11.3 diff --git a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs index de39dbae..5283340e 100644 --- a/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/BaseContentManager.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; @@ -264,6 +265,11 @@ namespace StardewModdingAPI.Framework.ContentManagers /// The language code for which to inject the asset. protected virtual void Inject(string assetName, T value, LanguageCode language) { + // track asset key + if (value is Texture2D texture) + texture.Name = assetName; + + // cache asset assetName = this.AssertAndNormalizeAssetName(assetName); this.Cache[assetName] = value; } diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 66e6ed14..c0d57f4b 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -507,6 +507,7 @@ namespace StardewModdingAPI.Metadata // find matches TAnimal[] animals = this.GetCharacters() .OfType() + .Where(p => key == this.GetNormalizedPath(p.Sprite?.Texture?.Name)) .ToArray(); if (!animals.Any()) return false; @@ -587,7 +588,7 @@ namespace StardewModdingAPI.Metadata let locCritters = this.Reflection.GetField>(location, "critters").GetValue() where locCritters != null from Critter critter in locCritters - where this.GetNormalizedPath(critter.sprite.textureName) == key + where this.GetNormalizedPath(critter.sprite?.Texture?.Name) == key select critter ) .ToArray(); @@ -673,7 +674,7 @@ namespace StardewModdingAPI.Metadata // get NPCs HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); NPC[] characters = this.GetCharacters() - .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalizedPath(npc.Sprite.textureName.Value))) + .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalizedPath(npc.Sprite?.Texture?.Name))) .ToArray(); if (!characters.Any()) return 0; @@ -697,36 +698,23 @@ namespace StardewModdingAPI.Metadata { // get NPCs HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); - var villagers = - ( - from npc in this.GetCharacters() - where npc.isVillager() - let textureKey = this.GetNormalizedPath($"Portraits\\{this.getTextureName(npc)}") - where lookup.Contains(textureKey) - select new { npc, textureKey } - ) + var villagers = this + .GetCharacters() + .Where(npc => npc.isVillager() && lookup.Contains(this.GetNormalizedPath(npc.Portrait?.Name))) .ToArray(); if (!villagers.Any()) return 0; // update portrait int reloaded = 0; - foreach (var entry in villagers) + foreach (NPC npc in villagers) { - entry.npc.resetPortrait(); - entry.npc.Portrait = content.Load(entry.textureKey); + npc.Portrait = content.Load(npc.Portrait.Name); reloaded++; } return reloaded; } - private string getTextureName(NPC npc) - { - string name = npc.Name; - string str = name == "Old Mariner" ? "Mariner" : (name == "Dwarf King" ? "DwarfKing" : (name == "Mister Qi" ? "MrQi" : (name == "???" ? "Monsters\\Shadow Guy" : name))); - return str; - } - /// Reload tree textures. /// The content manager through which to reload the asset. /// The asset key to reload. -- cgit From 083e68ad5bbbe966c904d6aec48ab6b92f69a531 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 9 Sep 2019 23:47:45 -0400 Subject: fix key errors during asset propagation in some cases --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 45 ++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index c0d57f4b..fceb840f 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -24,8 +24,8 @@ namespace StardewModdingAPI.Metadata /********* ** Fields *********/ - /// Normalizes an asset key to match the cache key. - private readonly Func GetNormalizedPath; + /// Normalizes an asset key to match the cache key and assert that it's valid. + private readonly Func AssertAndNormalizeAssetName; /// Simplifies access to private game code. private readonly Reflector Reflection; @@ -51,12 +51,12 @@ namespace StardewModdingAPI.Metadata ** Public methods *********/ /// Initialize the core asset data. - /// Normalizes an asset key to match the cache key. + /// Normalizes an asset key to match the cache key and assert that it's valid. /// Simplifies access to private code. /// Encapsulates monitoring and logging. - public CoreAssetPropagator(Func getNormalizedPath, Reflector reflection, IMonitor monitor) + public CoreAssetPropagator(Func assertAndNormalizeAssetName, Reflector reflection, IMonitor monitor) { - this.GetNormalizedPath = getNormalizedPath; + this.AssertAndNormalizeAssetName = assertAndNormalizeAssetName; this.Reflection = reflection; this.Monitor = monitor; } @@ -112,7 +112,7 @@ namespace StardewModdingAPI.Metadata /// Returns whether an asset was loaded. The return value may be true or false, or a non-null value for true. private bool PropagateOther(LocalizedContentManager content, string key, Type type) { - key = this.GetNormalizedPath(key); + key = this.AssertAndNormalizeAssetName(key); /**** ** Special case: current map tilesheet @@ -123,7 +123,7 @@ namespace StardewModdingAPI.Metadata { foreach (TileSheet tilesheet in Game1.currentLocation.map.TileSheets) { - if (this.GetNormalizedPath(tilesheet.ImageSource) == key) + if (this.NormalizeAssetNameIgnoringEmpty(tilesheet.ImageSource) == key) Game1.mapDisplayDevice.LoadTileSheet(tilesheet); } } @@ -136,7 +136,7 @@ namespace StardewModdingAPI.Metadata bool anyChanged = false; foreach (GameLocation location in this.GetLocations()) { - if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.GetNormalizedPath(location.mapPath.Value) == key) + if (!string.IsNullOrWhiteSpace(location.mapPath.Value) && this.NormalizeAssetNameIgnoringEmpty(location.mapPath.Value) == key) { // general updates location.reloadMap(); @@ -507,7 +507,7 @@ namespace StardewModdingAPI.Metadata // find matches TAnimal[] animals = this.GetCharacters() .OfType() - .Where(p => key == this.GetNormalizedPath(p.Sprite?.Texture?.Name)) + .Where(p => key == this.NormalizeAssetNameIgnoringEmpty(p.Sprite?.Texture?.Name)) .ToArray(); if (!animals.Any()) return false; @@ -588,7 +588,7 @@ namespace StardewModdingAPI.Metadata let locCritters = this.Reflection.GetField>(location, "critters").GetValue() where locCritters != null from Critter critter in locCritters - where this.GetNormalizedPath(critter.sprite?.Texture?.Name) == key + where this.NormalizeAssetNameIgnoringEmpty(critter.sprite?.Texture?.Name) == key select critter ) .ToArray(); @@ -653,11 +653,11 @@ namespace StardewModdingAPI.Metadata { IDictionary data = content.Load>(key); bool changed = false; - foreach (NPC character in this.GetCharacters()) + foreach (NPC npc in this.GetCharacters()) { - if (character.isVillager() && data.ContainsKey(character.Name)) + if (npc.isVillager() && data.ContainsKey(npc.Name)) { - character.reloadData(); + npc.reloadData(); changed = true; } } @@ -674,7 +674,7 @@ namespace StardewModdingAPI.Metadata // get NPCs HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); NPC[] characters = this.GetCharacters() - .Where(npc => npc.Sprite != null && lookup.Contains(this.GetNormalizedPath(npc.Sprite?.Texture?.Name))) + .Where(npc => npc.Sprite != null && lookup.Contains(this.NormalizeAssetNameIgnoringEmpty(npc.Sprite?.Texture?.Name))) .ToArray(); if (!characters.Any()) return 0; @@ -700,7 +700,7 @@ namespace StardewModdingAPI.Metadata HashSet lookup = new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); var villagers = this .GetCharacters() - .Where(npc => npc.isVillager() && lookup.Contains(this.GetNormalizedPath(npc.Portrait?.Name))) + .Where(npc => npc.isVillager() && lookup.Contains(this.NormalizeAssetNameIgnoringEmpty(npc.Portrait?.Name))) .ToArray(); if (!villagers.Any()) return 0; @@ -849,12 +849,25 @@ namespace StardewModdingAPI.Metadata } } + /// Normalize an asset key to match the cache key and assert that it's valid, but don't raise an error for null or empty values. + /// The asset key to normalize. + private string NormalizeAssetNameIgnoringEmpty(string path) + { + if (string.IsNullOrWhiteSpace(path)) + return null; + + return this.AssertAndNormalizeAssetName(path); + } + /// Get whether a key starts with a substring after the substring is normalized. /// The key to check. /// The substring to normalize and find. private bool KeyStartsWith(string key, string rawSubstring) { - return key.StartsWith(this.GetNormalizedPath(rawSubstring), StringComparison.InvariantCultureIgnoreCase); + if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(rawSubstring)) + return false; + + return key.StartsWith(this.NormalizeAssetNameIgnoringEmpty(rawSubstring), StringComparison.InvariantCultureIgnoreCase); } /// Get whether a normalized asset key is in the given folder. -- cgit From 3cf3df8ffb21afc7698427e51787324c5d237800 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 14 Sep 2019 23:18:03 -0400 Subject: fix ICursorPosition.AbsolutePixels not adjusted for zoom --- docs/release-notes.md | 1 + src/SMAPI/Framework/CursorPosition.cs | 8 ++++---- src/SMAPI/Framework/Input/SInputState.cs | 14 ++++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 45d65f7d..af8b1d5b 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -86,6 +86,7 @@ For modders: * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialized when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialized). * Removed all deprecated APIs. * Removed `Monitor.ExitGameImmediately`. + * Fixed `ICursorPosition.AbsolutePixels` not adjusted for zoom. * Changes: * Added support for content pack translations. * Added `IContentPack.HasFile`, `Context.IsGameLaunched`, and `SemanticVersion.TryParse`. diff --git a/src/SMAPI/Framework/CursorPosition.cs b/src/SMAPI/Framework/CursorPosition.cs index 079917f2..2008ccce 100644 --- a/src/SMAPI/Framework/CursorPosition.cs +++ b/src/SMAPI/Framework/CursorPosition.cs @@ -8,10 +8,10 @@ namespace StardewModdingAPI.Framework /********* ** Accessors *********/ - /// The pixel position relative to the top-left corner of the in-game map. + /// The pixel position relative to the top-left corner of the in-game map, adjusted for pixel zoom. public Vector2 AbsolutePixels { get; } - /// The pixel position relative to the top-left corner of the visible screen. + /// The pixel position relative to the top-left corner of the visible screen, adjusted for pixel zoom. public Vector2 ScreenPixels { get; } /// The tile position under the cursor relative to the top-left corner of the map. @@ -25,8 +25,8 @@ namespace StardewModdingAPI.Framework ** Public methods *********/ /// Construct an instance. - /// The pixel position relative to the top-left corner of the in-game map. - /// The pixel position relative to the top-left corner of the visible screen. + /// The pixel position relative to the top-left corner of the in-game map, adjusted for pixel zoom. + /// The pixel position relative to the top-left corner of the visible screen, adjusted for pixel zoom. /// The tile position relative to the top-left corner of the map. /// The tile position that the game considers under the cursor for purposes of clicking actions. public CursorPosition(Vector2 absolutePixels, Vector2 screenPixels, Vector2 tile, Vector2 grabTile) diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs index a15272d5..d69e5604 100644 --- a/src/SMAPI/Framework/Input/SInputState.cs +++ b/src/SMAPI/Framework/Input/SInputState.cs @@ -80,12 +80,14 @@ namespace StardewModdingAPI.Framework.Input { try { + float zoomMultiplier = (1f / Game1.options.zoomLevel); + // get new states GamePadState realController = GamePad.GetState(PlayerIndex.One); KeyboardState realKeyboard = Keyboard.GetState(); 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 cursorAbsolutePos = new Vector2((realMouse.X * zoomMultiplier) + Game1.viewport.X, (realMouse.Y * zoomMultiplier) + Game1.viewport.Y); Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.getTileLocation() : (Vector2?)null; // update real states @@ -96,7 +98,7 @@ namespace StardewModdingAPI.Framework.Input if (cursorAbsolutePos != this.CursorPositionImpl?.AbsolutePixels || playerTilePos != this.LastPlayerTile) { this.LastPlayerTile = playerTilePos; - this.CursorPositionImpl = this.GetCursorPosition(realMouse, cursorAbsolutePos); + this.CursorPositionImpl = this.GetCursorPosition(realMouse, cursorAbsolutePos, zoomMultiplier); } // update suppressed states @@ -170,11 +172,11 @@ namespace StardewModdingAPI.Framework.Input *********/ /// Get the current cursor position. /// The current mouse state. - /// The absolute pixel position relative to the map. - private CursorPosition GetCursorPosition(MouseState mouseState, Vector2 absolutePixels) + /// The absolute pixel position relative to the map, adjusted for pixel zoom. + /// The multiplier applied to pixel coordinates to adjust them for pixel zoom. + private CursorPosition GetCursorPosition(MouseState mouseState, Vector2 absolutePixels, float zoomMultiplier) { - Vector2 rawPixels = new Vector2(mouseState.X, mouseState.Y); - Vector2 screenPixels = rawPixels * new Vector2((float)1.0 / Game1.options.zoomLevel); // derived from Game1::getMouseX + Vector2 screenPixels = new Vector2(mouseState.X * zoomMultiplier, mouseState.Y * zoomMultiplier); Vector2 tile = new Vector2((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize)); Vector2 grabTile = (Game1.mouseCursorTransparency > 0 && Utility.tileWithinRadiusOfPlayer((int)tile.X, (int)tile.Y, 1, Game1.player)) // derived from Game1.pressActionButton ? tile -- cgit From 4e7a67bc6d616950fed03ba8c26f9dec2cc273ff Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 16 Sep 2019 16:28:12 -0400 Subject: log custom SMAPI settings to simplify troubleshooting --- docs/release-notes.md | 2 +- src/SMAPI/Framework/Models/SConfig.cs | 64 +++++++++++++++++++++++++++++++---- src/SMAPI/Framework/SCore.cs | 7 ++++ src/SMAPI/SMAPI.config.json | 1 + 4 files changed, 66 insertions(+), 8 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index af8b1d5b..ba64db0d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -43,7 +43,6 @@ For modders: * Improved mod scanning: * Now ignores metadata files and folders (like `__MACOSX` and `__folder_managed_by_vortex`) and content files (like `.txt` or `.png`), which avoids missing-manifest errors in some common cases. * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages. - * Added trace logs for skipped loose files so it's easier to troubleshoot player logs. * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. * The installer now recognises custom game paths stored in `stardewvalley.targets`. * Duplicate-mod errors now show the mod version in each folder. @@ -93,6 +92,7 @@ For modders: * Added separate `LogNetworkTraffic` option to make verbose logging less overwhelmingly verbose. * Added asset propagation for `Data\FarmAnimals`, critter textures, and `DayTimeMoneyBox` buttons. * Added `Texture2D.Name` values set to the asset key. + * Added trace logs for skipped loose files in the `Mods` folder and custom SMAPI settings so it's easier to troubleshoot player logs. * `Constants.TargetPlatform` now returns `Android` when playing on an Android device. * Trace logs for a broken mod now list all detected issues (instead of the first one). * Trace logs when loading mods are now more clear. diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs index 2bc71adf..40ed9512 100644 --- a/src/SMAPI/Framework/Models/SConfig.cs +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -1,3 +1,6 @@ +using System; +using System.Collections.Generic; +using System.Linq; using StardewModdingAPI.Internal.ConsoleWriting; namespace StardewModdingAPI.Framework.Models @@ -5,6 +8,35 @@ namespace StardewModdingAPI.Framework.Models /// The SMAPI configuration settings. internal class SConfig { + /******** + ** Fields + ********/ + /// The default config values, for fields that should be logged if different. + private static readonly IDictionary DefaultValues = new Dictionary + { + [nameof(CheckForUpdates)] = true, + [nameof(ParanoidWarnings)] = +#if DEBUG + true, +#else + false, +#endif + [nameof(UseBetaChannel)] = Constants.ApiVersion.IsPrerelease(), + [nameof(GitHubProjectName)] = "Pathoschild/SMAPI", + [nameof(WebApiBaseUrl)] = "https://api.smapi.io", + [nameof(VerboseLogging)] = false, + [nameof(LogNetworkTraffic)] = false, + [nameof(DumpMetadata)] = false + }; + + /// The default values for , to log changes if different. + private static readonly HashSet DefaultSuppressUpdateChecks = new HashSet(StringComparer.InvariantCultureIgnoreCase) + { + "SMAPI.ConsoleCommands", + "SMAPI.SaveBackup" + }; + + /******** ** Accessors ********/ @@ -15,15 +47,10 @@ namespace StardewModdingAPI.Framework.Models public bool CheckForUpdates { get; set; } /// Whether to add a section to the 'mod issues' list for mods which which directly use potentially sensitive .NET APIs like file or shell access. - public bool ParanoidWarnings { get; set; } = -#if DEBUG - true; -#else - false; -#endif + public bool ParanoidWarnings { get; set; } = (bool)SConfig.DefaultValues[nameof(SConfig.ParanoidWarnings)]; /// Whether to show beta versions as valid updates. - public bool UseBetaChannel { get; set; } = Constants.ApiVersion.IsPrerelease(); + public bool UseBetaChannel { get; set; } = (bool)SConfig.DefaultValues[nameof(SConfig.UseBetaChannel)]; /// SMAPI's GitHub project name, used to perform update checks. public string GitHubProjectName { get; set; } @@ -45,5 +72,28 @@ namespace StardewModdingAPI.Framework.Models /// The mod IDs SMAPI should ignore when performing update checks or validating update keys. public string[] SuppressUpdateChecks { get; set; } + + + /******** + ** Public methods + ********/ + /// Get the settings which have been customised by the player. + public IDictionary GetCustomSettings() + { + IDictionary custom = new Dictionary(); + + foreach (var pair in SConfig.DefaultValues) + { + object value = typeof(SConfig).GetProperty(pair.Key)?.GetValue(this); + if (!pair.Value.Equals(value)) + custom[pair.Key] = value; + } + + HashSet curSuppressUpdateChecks = new HashSet(this.SuppressUpdateChecks ?? new string[0], StringComparer.InvariantCultureIgnoreCase); + if (SConfig.DefaultSuppressUpdateChecks.Count != curSuppressUpdateChecks.Count || SConfig.DefaultSuppressUpdateChecks.Any(p => !curSuppressUpdateChecks.Contains(p))) + custom[nameof(this.SuppressUpdateChecks)] = "[" + string.Join(", ", this.SuppressUpdateChecks ?? new string[0]) + "]"; + + return custom; + } } } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index fde28852..08d30a29 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -164,6 +164,13 @@ namespace StardewModdingAPI.Framework this.Monitor.Log("(Using custom --mods-path argument.)", LogLevel.Trace); this.Monitor.Log($"Log started at {DateTime.UtcNow:s} UTC", LogLevel.Trace); + // log custom settings + { + IDictionary customSettings = this.Settings.GetCustomSettings(); + if (customSettings.Any()) + this.Monitor.Log($"Loaded with custom settings: {string.Join(", ", customSettings.OrderBy(p => p.Key).Select(p => $"{p.Key}: {p.Value}"))}", LogLevel.Trace); + } + // validate platform #if SMAPI_FOR_WINDOWS if (Constants.Platform != Platform.Windows) diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json index 450a32cc..225e4b3f 100644 --- a/src/SMAPI/SMAPI.config.json +++ b/src/SMAPI/SMAPI.config.json @@ -3,6 +3,7 @@ This file contains advanced configuration for SMAPI. You generally shouldn't change this file. +The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to log custom changes. -- cgit From e6edf8adc7bfe470c005af4a1f51217c0f355831 Mon Sep 17 00:00:00 2001 From: danvolchek Date: Sat, 14 Sep 2019 12:44:03 -0700 Subject: fix saving event doc typo --- src/SMAPI/Events/IGameLoopEvents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Events/IGameLoopEvents.cs b/src/SMAPI/Events/IGameLoopEvents.cs index a576895b..6855737b 100644 --- a/src/SMAPI/Events/IGameLoopEvents.cs +++ b/src/SMAPI/Events/IGameLoopEvents.cs @@ -26,7 +26,7 @@ namespace StardewModdingAPI.Events /// Raised after the game finishes creating the save file. event EventHandler SaveCreated; - /// Raised before the game begins writes data to the save file (except the initial save creation). + /// Raised before the game begins writing data to the save file (except the initial save creation). event EventHandler Saving; /// Raised after the game finishes writing data to the save file (except the initial save creation). -- cgit From 1b5055dfaafc6dcf77b5262b8290e8ca2c8179ed Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 23 Sep 2019 17:09:35 -0400 Subject: make console colors configurable --- docs/release-notes.md | 1 + src/SMAPI.Installer/InteractiveInstaller.cs | 8 +- .../ConsoleWriting/ColorSchemeConfig.cs | 15 ++++ .../ConsoleWriting/ColorfulConsoleWriter.cs | 88 +++++++++++++--------- .../ConsoleWriting/ConsoleLogLevel.cs | 30 ++++++++ src/SMAPI.Internal/ConsoleWriting/LogLevel.cs | 30 -------- src/SMAPI.Internal/SMAPI.Internal.projitems | 3 +- src/SMAPI/Framework/Models/SConfig.cs | 4 +- src/SMAPI/Framework/Monitor.cs | 6 +- src/SMAPI/Framework/SCore.cs | 4 +- src/SMAPI/SMAPI.config.json | 51 ++++++++++--- 11 files changed, 151 insertions(+), 89 deletions(-) create mode 100644 src/SMAPI.Internal/ConsoleWriting/ColorSchemeConfig.cs create mode 100644 src/SMAPI.Internal/ConsoleWriting/ConsoleLogLevel.cs delete mode 100644 src/SMAPI.Internal/ConsoleWriting/LogLevel.cs (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index ba64db0d..285384b0 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -43,6 +43,7 @@ For modders: * Improved mod scanning: * Now ignores metadata files and folders (like `__MACOSX` and `__folder_managed_by_vortex`) and content files (like `.txt` or `.png`), which avoids missing-manifest errors in some common cases. * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages. + * Added support for configuring console colors via `smapi-internal/config.json` (intended for players with unusual consoles). * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. * The installer now recognises custom game paths stored in `stardewvalley.targets`. * Duplicate-mod errors now show the mod version in each folder. diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 4d313a3b..964300ac 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -100,7 +100,7 @@ namespace StardewModdingApi.Installer public InteractiveInstaller(string bundlePath) { this.BundlePath = bundlePath; - this.ConsoleWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.AutoDetect); + this.ConsoleWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform()); } /// Run the install or uninstall script. @@ -217,8 +217,8 @@ namespace StardewModdingApi.Installer ** show theme selector ****/ // get theme writers - var lightBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.LightBackground); - var darkBackgroundWriter = new ColorfulConsoleWriter(EnvironmentUtility.DetectPlatform(), MonitorColorScheme.DarkBackground); + var lightBackgroundWriter = new ColorfulConsoleWriter(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.LightBackground)); + var darkBackgroundWriter = new ColorfulConsoleWriter(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.DarkBackground)); // print question this.PrintPlain("Which text looks more readable?"); @@ -470,7 +470,7 @@ namespace StardewModdingApi.Installer { string text = File .ReadAllText(paths.ApiConfigPath) - .Replace(@"""ColorScheme"": ""AutoDetect""", $@"""ColorScheme"": ""{scheme}"""); + .Replace(@"""UseScheme"": ""AutoDetect""", $@"""UseScheme"": ""{scheme}"""); File.WriteAllText(paths.ApiConfigPath, text); } diff --git a/src/SMAPI.Internal/ConsoleWriting/ColorSchemeConfig.cs b/src/SMAPI.Internal/ConsoleWriting/ColorSchemeConfig.cs new file mode 100644 index 00000000..001840bf --- /dev/null +++ b/src/SMAPI.Internal/ConsoleWriting/ColorSchemeConfig.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace StardewModdingAPI.Internal.ConsoleWriting +{ + /// The console color scheme options. + internal class ColorSchemeConfig + { + /// The default color scheme ID to use, or to select one automatically. + public MonitorColorScheme UseScheme { get; set; } + + /// The available console color schemes. + public IDictionary> Schemes { get; set; } + } +} diff --git a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs index db016bae..aefda9b6 100644 --- a/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs +++ b/src/SMAPI.Internal/ConsoleWriting/ColorfulConsoleWriter.cs @@ -22,11 +22,16 @@ namespace StardewModdingAPI.Internal.ConsoleWriting *********/ /// Construct an instance. /// The target platform. - /// The console color scheme to use. - public ColorfulConsoleWriter(Platform platform, MonitorColorScheme colorScheme) + public ColorfulConsoleWriter(Platform platform) + : this(platform, ColorfulConsoleWriter.GetDefaultColorSchemeConfig(MonitorColorScheme.AutoDetect)) { } + + /// Construct an instance. + /// The target platform. + /// The colors to use for text written to the SMAPI console. + public ColorfulConsoleWriter(Platform platform, ColorSchemeConfig colorConfig) { this.SupportsColor = this.TestColorSupport(); - this.Colors = this.GetConsoleColorScheme(platform, colorScheme); + this.Colors = this.GetConsoleColorScheme(platform, colorConfig); } /// Write a message line to the log. @@ -54,6 +59,40 @@ namespace StardewModdingAPI.Internal.ConsoleWriting Console.WriteLine(message); } + /// Get the default color scheme config for cases where it's not configurable (e.g. the installer). + /// The default color scheme ID to use, or to select one automatically. + /// The colors here should be kept in sync with the SMAPI config file. + public static ColorSchemeConfig GetDefaultColorSchemeConfig(MonitorColorScheme useScheme) + { + return new ColorSchemeConfig + { + UseScheme = useScheme, + Schemes = new Dictionary> + { + [MonitorColorScheme.DarkBackground] = new Dictionary + { + [ConsoleLogLevel.Trace] = ConsoleColor.DarkGray, + [ConsoleLogLevel.Debug] = ConsoleColor.DarkGray, + [ConsoleLogLevel.Info] = ConsoleColor.White, + [ConsoleLogLevel.Warn] = ConsoleColor.Yellow, + [ConsoleLogLevel.Error] = ConsoleColor.Red, + [ConsoleLogLevel.Alert] = ConsoleColor.Magenta, + [ConsoleLogLevel.Success] = ConsoleColor.DarkGreen + }, + [MonitorColorScheme.LightBackground] = new Dictionary + { + [ConsoleLogLevel.Trace] = ConsoleColor.DarkGray, + [ConsoleLogLevel.Debug] = ConsoleColor.DarkGray, + [ConsoleLogLevel.Info] = ConsoleColor.Black, + [ConsoleLogLevel.Warn] = ConsoleColor.DarkYellow, + [ConsoleLogLevel.Error] = ConsoleColor.Red, + [ConsoleLogLevel.Alert] = ConsoleColor.DarkMagenta, + [ConsoleLogLevel.Success] = ConsoleColor.DarkGreen + } + } + }; + } + /********* ** Private methods @@ -74,47 +113,22 @@ namespace StardewModdingAPI.Internal.ConsoleWriting /// Get the color scheme to use for the current console. /// The target platform. - /// The console color scheme to use. - private IDictionary GetConsoleColorScheme(Platform platform, MonitorColorScheme colorScheme) + /// The colors to use for text written to the SMAPI console. + private IDictionary GetConsoleColorScheme(Platform platform, ColorSchemeConfig colorConfig) { - // auto detect color scheme - if (colorScheme == MonitorColorScheme.AutoDetect) + // get color scheme ID + MonitorColorScheme schemeID = colorConfig.UseScheme; + if (schemeID == MonitorColorScheme.AutoDetect) { - colorScheme = platform == Platform.Mac + schemeID = platform == Platform.Mac ? MonitorColorScheme.LightBackground // MacOS doesn't provide console background color info, but it's usually white. : ColorfulConsoleWriter.IsDark(Console.BackgroundColor) ? MonitorColorScheme.DarkBackground : MonitorColorScheme.LightBackground; } // get colors for scheme - switch (colorScheme) - { - case MonitorColorScheme.DarkBackground: - return new Dictionary - { - [ConsoleLogLevel.Trace] = ConsoleColor.DarkGray, - [ConsoleLogLevel.Debug] = ConsoleColor.DarkGray, - [ConsoleLogLevel.Info] = ConsoleColor.White, - [ConsoleLogLevel.Warn] = ConsoleColor.Yellow, - [ConsoleLogLevel.Error] = ConsoleColor.Red, - [ConsoleLogLevel.Alert] = ConsoleColor.Magenta, - [ConsoleLogLevel.Success] = ConsoleColor.DarkGreen - }; - - case MonitorColorScheme.LightBackground: - return new Dictionary - { - [ConsoleLogLevel.Trace] = ConsoleColor.DarkGray, - [ConsoleLogLevel.Debug] = ConsoleColor.DarkGray, - [ConsoleLogLevel.Info] = ConsoleColor.Black, - [ConsoleLogLevel.Warn] = ConsoleColor.DarkYellow, - [ConsoleLogLevel.Error] = ConsoleColor.Red, - [ConsoleLogLevel.Alert] = ConsoleColor.DarkMagenta, - [ConsoleLogLevel.Success] = ConsoleColor.DarkGreen - }; - - default: - throw new NotSupportedException($"Unknown color scheme '{colorScheme}'."); - } + return colorConfig.Schemes.TryGetValue(schemeID, out IDictionary scheme) + ? scheme + : throw new NotSupportedException($"Unknown color scheme '{schemeID}'."); } /// Get whether a console color should be considered dark, which is subjectively defined as 'white looks better than black on this text'. diff --git a/src/SMAPI.Internal/ConsoleWriting/ConsoleLogLevel.cs b/src/SMAPI.Internal/ConsoleWriting/ConsoleLogLevel.cs new file mode 100644 index 00000000..54564111 --- /dev/null +++ b/src/SMAPI.Internal/ConsoleWriting/ConsoleLogLevel.cs @@ -0,0 +1,30 @@ +namespace StardewModdingAPI.Internal.ConsoleWriting +{ + /// The log severity levels. + internal enum ConsoleLogLevel + { + /// Tracing info intended for developers. + Trace, + + /// Troubleshooting info that may be relevant to the player. + Debug, + + /// Info relevant to the player. This should be used judiciously. + Info, + + /// An issue the player should be aware of. This should be used rarely. + Warn, + + /// A message indicating something went wrong. + Error, + + /// Important information to highlight for the player when player action is needed (e.g. new version available). This should be used rarely to avoid alert fatigue. + Alert, + + /// A critical issue that generally signals an immediate end to the application. + Critical, + + /// A success message that generally signals a successful end to a task. + Success + } +} diff --git a/src/SMAPI.Internal/ConsoleWriting/LogLevel.cs b/src/SMAPI.Internal/ConsoleWriting/LogLevel.cs deleted file mode 100644 index 54564111..00000000 --- a/src/SMAPI.Internal/ConsoleWriting/LogLevel.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace StardewModdingAPI.Internal.ConsoleWriting -{ - /// The log severity levels. - internal enum ConsoleLogLevel - { - /// Tracing info intended for developers. - Trace, - - /// Troubleshooting info that may be relevant to the player. - Debug, - - /// Info relevant to the player. This should be used judiciously. - Info, - - /// An issue the player should be aware of. This should be used rarely. - Warn, - - /// A message indicating something went wrong. - Error, - - /// Important information to highlight for the player when player action is needed (e.g. new version available). This should be used rarely to avoid alert fatigue. - Alert, - - /// A critical issue that generally signals an immediate end to the application. - Critical, - - /// A success message that generally signals a successful end to a task. - Success - } -} diff --git a/src/SMAPI.Internal/SMAPI.Internal.projitems b/src/SMAPI.Internal/SMAPI.Internal.projitems index 1408cc46..7fcebc94 100644 --- a/src/SMAPI.Internal/SMAPI.Internal.projitems +++ b/src/SMAPI.Internal/SMAPI.Internal.projitems @@ -10,7 +10,8 @@ - + + \ No newline at end of file diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs index 40ed9512..b778af5d 100644 --- a/src/SMAPI/Framework/Models/SConfig.cs +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -67,8 +67,8 @@ namespace StardewModdingAPI.Framework.Models /// Whether to generate a file in the mods folder with detailed metadata about the detected mods. public bool DumpMetadata { get; set; } - /// The console color scheme to use. - public MonitorColorScheme ColorScheme { get; set; } + /// The colors to use for text written to the SMAPI console. + public ColorSchemeConfig ConsoleColors { get; set; } /// The mod IDs SMAPI should ignore when performing update checks or validating update keys. public string[] SuppressUpdateChecks { get; set; } diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs index 1fa55a9e..06cf1b46 100644 --- a/src/SMAPI/Framework/Monitor.cs +++ b/src/SMAPI/Framework/Monitor.cs @@ -50,9 +50,9 @@ namespace StardewModdingAPI.Framework /// The name of the module which logs messages using this instance. /// Intercepts access to the console output. /// The log file to which to write messages. - /// The console color scheme to use. + /// The colors to use for text written to the SMAPI console. /// Whether verbose logging is enabled. This enables more detailed diagnostic messages than are normally needed. - public Monitor(string source, ConsoleInterceptionManager consoleInterceptor, LogFileManager logFile, MonitorColorScheme colorScheme, bool isVerbose) + public Monitor(string source, ConsoleInterceptionManager consoleInterceptor, LogFileManager logFile, ColorSchemeConfig colorConfig, bool isVerbose) { // validate if (string.IsNullOrWhiteSpace(source)) @@ -61,7 +61,7 @@ namespace StardewModdingAPI.Framework // initialize this.Source = source; this.LogFile = logFile ?? throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null."); - this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorScheme); + this.ConsoleWriter = new ColorfulConsoleWriter(Constants.Platform, colorConfig); this.ConsoleInterceptor = consoleInterceptor; this.IsVerbose = isVerbose; } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 08d30a29..e293cefd 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -143,7 +143,7 @@ namespace StardewModdingAPI.Framework // init basics this.Settings = JsonConvert.DeserializeObject(File.ReadAllText(Constants.ApiConfigPath)); this.LogFile = new LogFileManager(logPath); - this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.Settings.ColorScheme, this.Settings.VerboseLogging) + this.Monitor = new Monitor("SMAPI", this.ConsoleManager, this.LogFile, this.Settings.ConsoleColors, this.Settings.VerboseLogging) { WriteToConsole = writeToConsole, ShowTraceInConsole = this.Settings.DeveloperMode, @@ -1351,7 +1351,7 @@ namespace StardewModdingAPI.Framework /// The name of the module which will log messages with this instance. private Monitor GetSecondaryMonitor(string name) { - return new Monitor(name, this.ConsoleManager, this.LogFile, this.Settings.ColorScheme, this.Settings.VerboseLogging) + return new Monitor(name, this.ConsoleManager, this.LogFile, this.Settings.ConsoleColors, this.Settings.VerboseLogging) { WriteToConsole = this.Monitor.WriteToConsole, ShowTraceInConsole = this.Settings.DeveloperMode, diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json index 225e4b3f..bccac678 100644 --- a/src/SMAPI/SMAPI.config.json +++ b/src/SMAPI/SMAPI.config.json @@ -10,12 +10,9 @@ The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to */ { /** - * The console color theme to use. The possible values are: - * - AutoDetect: SMAPI will assume a light background on Mac, and detect the background color automatically on Linux or Windows. - * - LightBackground: use darker text colors that look better on a white or light background. - * - DarkBackground: use lighter text colors that look better on a black or dark background. + * Whether SMAPI should log more information about the game context. */ - "ColorScheme": "AutoDetect", + "VerboseLogging": false, /** * Whether SMAPI should check for newer versions of SMAPI and mods when you load the game. If new @@ -57,11 +54,6 @@ The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to */ "WebApiBaseUrl": "https://api.smapi.io", - /** - * Whether SMAPI should log more information about the game context. - */ - "VerboseLogging": false, - /** * Whether SMAPI should log network traffic (may be very verbose). Best combined with VerboseLogging, which includes network metadata. */ @@ -73,6 +65,45 @@ The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to */ "DumpMetadata": false, + /** + * The colors to use for text written to the SMAPI console. + * + * The possible values for 'UseScheme' are: + * - AutoDetect: SMAPI will assume a light background on Mac, and detect the background color + * automatically on Linux or Windows. + * - LightBackground: use darker text colors that look better on a white or light background. + * - DarkBackground: use lighter text colors that look better on a black or dark background. + * + * For available color codes, see https://docs.microsoft.com/en-us/dotnet/api/system.consolecolor. + * + * (These values are synched with ColorfulConsoleWriter.GetDefaultColorSchemeConfig in the + * SMAPI code.) + */ + "ConsoleColors": { + "UseScheme": "AutoDetect", + + "Schemes": { + "DarkBackground": { + "Trace": "DarkGray", + "Debug": "DarkGray", + "Info": "White", + "Warn": "Yellow", + "Error": "Red", + "Alert": "Magenta", + "Success": "DarkGreen" + }, + "LightBackground": { + "Trace": "DarkGray", + "Debug": "DarkGray", + "Info": "Black", + "Warn": "DarkYellow", + "Error": "Red", + "Alert": "DarkMagenta", + "Success": "DarkGreen" + } + } + }, + /** * The mod IDs SMAPI should ignore when performing update checks or validating update keys. */ -- cgit From 9461494a35b789c679a799fc9c5db2321d19d803 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 26 Sep 2019 19:48:01 -0400 Subject: auto-fix save data when a custom NPC mod is removed --- docs/README.md | 11 ++-- docs/release-notes.md | 9 +++- src/SMAPI/Framework/SCore.cs | 3 +- src/SMAPI/Patches/DialogueErrorPatch.cs | 9 ++-- src/SMAPI/Patches/EventErrorPatch.cs | 7 +-- src/SMAPI/Patches/LoadContextPatch.cs | 7 ++- src/SMAPI/Patches/LoadErrorPatch.cs | 94 +++++++++++++++++++++++++++++++++ src/SMAPI/Patches/ObjectErrorPatch.cs | 9 ++-- 8 files changed, 127 insertions(+), 22 deletions(-) create mode 100644 src/SMAPI/Patches/LoadErrorPatch.cs (limited to 'src/SMAPI') diff --git a/docs/README.md b/docs/README.md index 4b9c97a1..625e7eeb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -20,10 +20,13 @@ doesn't change any of your game files. It serves eight main purposes: many mods, and rewrites the mod so it's compatible._ 5. **Intercept errors.** - _SMAPI intercepts errors that happen in the game, displays the error details in the console - window, and in most cases automatically recovers the game. This prevents mods from accidentally - crashing the game, and makes it possible to troubleshoot errors in the game itself that would - otherwise show a generic 'program has stopped working' type of message._ + _SMAPI intercepts errors, shows the error info in the SMAPI console, and in most cases + automatically recovers the game. That prevents mods from crashing the game, and makes it + possible to troubleshoot errors in the game itself that would otherwise show a generic 'program + has stopped working' type of message._ + + _That also includes automatically fixing save data when a load would crash, e.g. due to a custom + NPC mod the player removed._ 6. **Provide update checks.** _SMAPI automatically checks for new versions of your installed mods, and notifies you when any diff --git a/docs/release-notes.md b/docs/release-notes.md index 285384b0..2a1b333e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,12 +8,16 @@ These changes have not been released yet. For players: * **Updated for Stardew Valley 1.4.** SMAPI 3.0 adds compatibility with the latest game version, and improves mod APIs using changes in the game code. + * **Improved performance.** SMAPI should have less impact on game performance and startup time for some players. + * **Added more error recovery.** - SMAPI now detects and prevents more crashes due to game or mod bugs. + SMAPI now detects and prevents more crashes due to game or mod bugs, or due to removing some mods which add custom content. + * **Improved mod scanning.** SMAPI now supports some non-standard mod structures automatically, improves compatibility with the Vortex mod manager, and improves various error/skip messages related to mod loading. + * **Fixed many bugs and edge cases.** For modders: @@ -39,11 +43,12 @@ For modders: * Changes: * Updated for Stardew Valley 1.4. * Improved performance. - * Rewrote launch script on Linux to improve compatibility (thanks to kurumushi and toastal!). * Improved mod scanning: * Now ignores metadata files and folders (like `__MACOSX` and `__folder_managed_by_vortex`) and content files (like `.txt` or `.png`), which avoids missing-manifest errors in some common cases. * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages. + * SMAPI now automatically fixes your save if you remove a custom NPC mod. (Invalid NPCs are now removed on load, with a warning in the console.) * Added support for configuring console colors via `smapi-internal/config.json` (intended for players with unusual consoles). + * Improved launch script compatibility on Linux (thanks to kurumushi and toastal!). * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. * The installer now recognises custom game paths stored in `stardewvalley.targets`. * Duplicate-mod errors now show the mod version in each folder. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index e293cefd..bc893abc 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -239,7 +239,8 @@ namespace StardewModdingAPI.Framework new EventErrorPatch(this.MonitorForGame), new DialogueErrorPatch(this.MonitorForGame, this.Reflection), new ObjectErrorPatch(), - new LoadContextPatch(this.Reflection, this.GameInstance.OnLoadStageChanged) + new LoadContextPatch(this.Reflection, this.GameInstance.OnLoadStageChanged), + new LoadErrorPatch(this.Monitor) ); // add exit handler diff --git a/src/SMAPI/Patches/DialogueErrorPatch.cs b/src/SMAPI/Patches/DialogueErrorPatch.cs index f1c25c05..24f97259 100644 --- a/src/SMAPI/Patches/DialogueErrorPatch.cs +++ b/src/SMAPI/Patches/DialogueErrorPatch.cs @@ -10,6 +10,9 @@ using StardewValley; namespace StardewModdingAPI.Patches { /// A Harmony patch for the constructor which intercepts invalid dialogue lines and logs an error instead of crashing. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] internal class DialogueErrorPatch : IHarmonyPatch { /********* @@ -29,7 +32,7 @@ namespace StardewModdingAPI.Patches ** Accessors *********/ /// A unique name for this patch. - public string Name => $"{nameof(DialogueErrorPatch)}"; + public string Name => nameof(DialogueErrorPatch); /********* @@ -68,8 +71,6 @@ namespace StardewModdingAPI.Patches /// The dialogue being parsed. /// The NPC for which the dialogue is being parsed. /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")] private static bool Before_Dialogue_Constructor(Dialogue __instance, string masterDialogue, NPC speaker) { // get private members @@ -109,8 +110,6 @@ namespace StardewModdingAPI.Patches /// The return value of the original method. /// The method being wrapped. /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")] private static bool Before_NPC_CurrentDialogue(NPC __instance, ref Stack __result, MethodInfo __originalMethod) { if (DialogueErrorPatch.IsInterceptingCurrentDialogue) diff --git a/src/SMAPI/Patches/EventErrorPatch.cs b/src/SMAPI/Patches/EventErrorPatch.cs index cd530616..1dc7e8c3 100644 --- a/src/SMAPI/Patches/EventErrorPatch.cs +++ b/src/SMAPI/Patches/EventErrorPatch.cs @@ -7,6 +7,9 @@ using StardewValley; namespace StardewModdingAPI.Patches { /// A Harmony patch for the constructor which intercepts invalid dialogue lines and logs an error instead of crashing. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] internal class EventErrorPatch : IHarmonyPatch { /********* @@ -23,7 +26,7 @@ namespace StardewModdingAPI.Patches ** Accessors *********/ /// A unique name for this patch. - public string Name => $"{nameof(EventErrorPatch)}"; + public string Name => nameof(EventErrorPatch); /********* @@ -56,8 +59,6 @@ namespace StardewModdingAPI.Patches /// The precondition to be parsed. /// The method being wrapped. /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")] private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) { if (EventErrorPatch.IsIntercepted) diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs index 93a059aa..0cc8c8eb 100644 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using Harmony; using StardewModdingAPI.Enums; using StardewModdingAPI.Framework.Patching; @@ -10,7 +11,9 @@ using StardewValley.Minigames; namespace StardewModdingAPI.Patches { /// 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. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] internal class LoadContextPatch : IHarmonyPatch { /********* @@ -27,7 +30,7 @@ namespace StardewModdingAPI.Patches ** Accessors *********/ /// A unique name for this patch. - public string Name => $"{nameof(LoadContextPatch)}"; + public string Name => nameof(LoadContextPatch); /********* diff --git a/src/SMAPI/Patches/LoadErrorPatch.cs b/src/SMAPI/Patches/LoadErrorPatch.cs new file mode 100644 index 00000000..87e8ee14 --- /dev/null +++ b/src/SMAPI/Patches/LoadErrorPatch.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Harmony; +using StardewModdingAPI.Framework.Patching; +using StardewValley; +using StardewValley.Locations; + +namespace StardewModdingAPI.Patches +{ + /// A Harmony patch for which prevents some errors due to broken save data. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + internal class LoadErrorPatch : IHarmonyPatch + { + /********* + ** Fields + *********/ + /// Writes messages to the console and log file. + private static IMonitor Monitor; + + + /********* + ** Accessors + *********/ + /// A unique name for this patch. + public string Name => nameof(LoadErrorPatch); + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Writes messages to the console and log file. + public LoadErrorPatch(IMonitor monitor) + { + LoadErrorPatch.Monitor = monitor; + } + + + /// Apply the Harmony patch. + /// The Harmony instance. + public void Apply(HarmonyInstance harmony) + { + harmony.Patch( + original: AccessTools.Method(typeof(SaveGame), nameof(SaveGame.loadDataToLocations)), + prefix: new HarmonyMethod(this.GetType(), nameof(LoadErrorPatch.Before_SaveGame_LoadDataToLocations)) + ); + } + + + /********* + ** Private methods + *********/ + /// The method to call instead of . + /// The game locations being loaded. + /// Returns whether to execute the original method. + private static bool Before_SaveGame_LoadDataToLocations(List gamelocations) + { + // get building interiors + var interiors = + ( + from location in gamelocations.OfType() + from building in location.buildings + where building.indoors.Value != null + select building.indoors.Value + ); + + // remove custom NPCs which no longer exist + IDictionary data = Game1.content.Load>("Data\\NPCDispositions"); + foreach (GameLocation location in gamelocations.Concat(interiors)) + { + foreach (NPC npc in location.characters.ToArray()) + { + if (npc.isVillager() && !data.ContainsKey(npc.Name)) + { + try + { + npc.reloadSprite(); // this won't crash for special villagers like Bouncer + } + catch + { + LoadErrorPatch.Monitor.Log($"Removed invalid villager '{npc.Name}' to avoid a crash when loading save '{Constants.SaveFolderName}'. (Did you remove a custom NPC mod?)", LogLevel.Warn); + location.characters.Remove(npc); + } + } + } + } + + return true; + } + } +} diff --git a/src/SMAPI/Patches/ObjectErrorPatch.cs b/src/SMAPI/Patches/ObjectErrorPatch.cs index 5b918d39..d716b29b 100644 --- a/src/SMAPI/Patches/ObjectErrorPatch.cs +++ b/src/SMAPI/Patches/ObjectErrorPatch.cs @@ -8,13 +8,16 @@ using SObject = StardewValley.Object; namespace StardewModdingAPI.Patches { /// A Harmony patch for which intercepts crashes due to the item no longer existing. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] internal class ObjectErrorPatch : IHarmonyPatch { /********* ** Accessors *********/ /// A unique name for this patch. - public string Name => $"{nameof(ObjectErrorPatch)}"; + public string Name => nameof(ObjectErrorPatch); /********* @@ -45,8 +48,6 @@ namespace StardewModdingAPI.Patches /// The instance being patched. /// The patched method's return value. /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")] private static bool Before_Object_GetDescription(SObject __instance, ref string __result) { // invalid bigcraftables crash instead of showing '???' like invalid non-bigcraftables @@ -63,8 +64,6 @@ namespace StardewModdingAPI.Patches /// The instance being patched. /// The item for which to draw a tooltip. /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")] private static bool Before_IClickableMenu_DrawTooltip(IClickableMenu __instance, Item hoveredItem) { // invalid edible item cause crash when drawing tooltips -- cgit From 673510b3941dd35a127e4f4a8a406f34b72b6a66 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 1 Oct 2019 20:04:58 -0400 Subject: remove unused translation field & method --- docs/release-notes.md | 2 +- src/SMAPI.Tests/Core/TranslationTests.cs | 49 +++++++------------ .../Framework/ModHelpers/TranslationHelper.cs | 13 ++--- src/SMAPI/Framework/SCore.cs | 6 +-- src/SMAPI/Translation.cs | 55 +++++++++------------- 5 files changed, 47 insertions(+), 78 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 2a1b333e..26645210 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -90,7 +90,7 @@ For modders: * Breaking changes: * Mods are now loaded much earlier in the game launch. This lets mods intercept any content asset, but the game is not fully initialized when `Entry` is called (use the `GameLaunched` event if you need to run code when the game is initialized). * Removed all deprecated APIs. - * Removed `Monitor.ExitGameImmediately`. + * Removed unused APIs: `Monitor.ExitGameImmediately`, `Translation.ModName`, and `Translation.Assert`. * Fixed `ICursorPosition.AbsolutePixels` not adjusted for zoom. * Changes: * Added support for content pack translations. diff --git a/src/SMAPI.Tests/Core/TranslationTests.cs b/src/SMAPI.Tests/Core/TranslationTests.cs index c098aca5..457f9fad 100644 --- a/src/SMAPI.Tests/Core/TranslationTests.cs +++ b/src/SMAPI.Tests/Core/TranslationTests.cs @@ -32,7 +32,7 @@ namespace SMAPI.Tests.Core var data = new Dictionary>(); // act - ITranslationHelper helper = new TranslationHelper("ModID", "ModName", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); + ITranslationHelper helper = new TranslationHelper("ModID", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); Translation translation = helper.Get("key"); Translation[] translationList = helper.GetTranslations()?.ToArray(); @@ -55,7 +55,7 @@ namespace SMAPI.Tests.Core // act var actual = new Dictionary(); - TranslationHelper helper = new TranslationHelper("ModID", "ModName", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); + TranslationHelper helper = new TranslationHelper("ModID", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); foreach (string locale in expected.Keys) { this.AssertSetLocale(helper, locale, LocalizedContentManager.LanguageCode.en); @@ -79,7 +79,7 @@ namespace SMAPI.Tests.Core // act var actual = new Dictionary(); - TranslationHelper helper = new TranslationHelper("ModID", "ModName", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); + TranslationHelper helper = new TranslationHelper("ModID", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); foreach (string locale in expected.Keys) { this.AssertSetLocale(helper, locale, LocalizedContentManager.LanguageCode.en); @@ -109,14 +109,14 @@ namespace SMAPI.Tests.Core [TestCase(" boop ", ExpectedResult = true)] public bool Translation_HasValue(string text) { - return new Translation("ModName", "pt-BR", "key", text).HasValue(); + return new Translation("pt-BR", "key", text).HasValue(); } [Test(Description = "Assert that the translation's ToString method returns the expected text for various inputs.")] public void Translation_ToString([ValueSource(nameof(TranslationTests.Samples))] string text) { // act - Translation translation = new Translation("ModName", "pt-BR", "key", text); + Translation translation = new Translation("pt-BR", "key", text); // assert if (translation.HasValue()) @@ -129,7 +129,7 @@ namespace SMAPI.Tests.Core public void Translation_ImplicitStringConversion([ValueSource(nameof(TranslationTests.Samples))] string text) { // act - Translation translation = new Translation("ModName", "pt-BR", "key", text); + Translation translation = new Translation("pt-BR", "key", text); // assert if (translation.HasValue()) @@ -142,7 +142,7 @@ namespace SMAPI.Tests.Core public void Translation_UsePlaceholder([Values(true, false)] bool value, [ValueSource(nameof(TranslationTests.Samples))] string text) { // act - Translation translation = new Translation("ModName", "pt-BR", "key", text).UsePlaceholder(value); + Translation translation = new Translation("pt-BR", "key", text).UsePlaceholder(value); // assert if (translation.HasValue()) @@ -153,24 +153,11 @@ namespace SMAPI.Tests.Core Assert.AreEqual(this.GetPlaceholderText("key"), translation.ToString(), "The translation returned an unexpected value given a null or empty input with the placeholder enabled."); } - [Test(Description = "Assert that the translation's Assert method throws the expected exception.")] - public void Translation_Assert([ValueSource(nameof(TranslationTests.Samples))] string text) - { - // act - Translation translation = new Translation("ModName", "pt-BR", "key", text); - - // assert - if (translation.HasValue()) - Assert.That(() => translation.Assert(), Throws.Nothing, "The assert unexpected threw an exception for a valid input."); - else - Assert.That(() => translation.Assert(), Throws.Exception.TypeOf(), "The assert didn't throw an exception for invalid input."); - } - [Test(Description = "Assert that the translation returns the expected text after setting the default.")] public void Translation_Default([ValueSource(nameof(TranslationTests.Samples))] string text, [ValueSource(nameof(TranslationTests.Samples))] string @default) { // act - Translation translation = new Translation("ModName", "pt-BR", "key", text).Default(@default); + Translation translation = new Translation("pt-BR", "key", text).Default(@default); // assert if (!string.IsNullOrEmpty(text)) @@ -195,7 +182,7 @@ namespace SMAPI.Tests.Core string expected = $"{start} tokens are properly replaced (including {middle} {middle}) {end}"; // act - Translation translation = new Translation("ModName", "pt-BR", "key", input); + Translation translation = new Translation("pt-BR", "key", input); switch (structure) { case "anonymous object": @@ -236,7 +223,7 @@ namespace SMAPI.Tests.Core string value = Guid.NewGuid().ToString("N"); // act - Translation translation = new Translation("ModName", "pt-BR", "key", text).Tokens(new Dictionary { [key] = value }); + Translation translation = new Translation("pt-BR", "key", text).Tokens(new Dictionary { [key] = value }); // assert Assert.AreEqual(value, translation.ToString(), "The translation returned an unexpected value given a valid base text."); @@ -252,7 +239,7 @@ namespace SMAPI.Tests.Core string value = Guid.NewGuid().ToString("N"); // act - Translation translation = new Translation("ModName", "pt-BR", "key", text).Tokens(new Dictionary { [key] = value }); + Translation translation = new Translation("pt-BR", "key", text).Tokens(new Dictionary { [key] = value }); // assert Assert.AreEqual(value, translation.ToString(), "The translation returned an unexpected value given a valid base text."); @@ -303,19 +290,19 @@ namespace SMAPI.Tests.Core { ["default"] = new[] { - new Translation(string.Empty, "default", "key A", "default A"), - new Translation(string.Empty, "default", "key C", "default C") + new Translation("default", "key A", "default A"), + new Translation("default", "key C", "default C") }, ["en"] = new[] { - new Translation(string.Empty, "en", "key A", "en A"), - new Translation(string.Empty, "en", "key B", "en B"), - new Translation(string.Empty, "en", "key C", "default C") + new Translation("en", "key A", "en A"), + new Translation("en", "key B", "en B"), + new Translation("en", "key C", "default C") }, ["zzz"] = new[] { - new Translation(string.Empty, "zzz", "key A", "zzz A"), - new Translation(string.Empty, "zzz", "key C", "default C") + new Translation("zzz", "key A", "zzz A"), + new Translation("zzz", "key C", "default C") } }; expected["en-us"] = expected["en"].ToArray(); diff --git a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs index 3252e047..65850384 100644 --- a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs @@ -11,9 +11,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /********* ** Fields *********/ - /// The name of the relevant mod for error messages. - private readonly string ModName; - /// The translations for each locale. private readonly IDictionary> All = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); @@ -36,15 +33,11 @@ namespace StardewModdingAPI.Framework.ModHelpers *********/ /// Construct an instance. /// The unique ID of the relevant mod. - /// The name of the relevant mod for error messages. /// The initial locale. /// The game's current language code. - public TranslationHelper(string modID, string modName, string locale, LocalizedContentManager.LanguageCode languageCode) + public TranslationHelper(string modID, string locale, LocalizedContentManager.LanguageCode languageCode) : base(modID) { - // save data - this.ModName = modName; - // set locale this.SetLocale(locale, languageCode); } @@ -60,7 +53,7 @@ namespace StardewModdingAPI.Framework.ModHelpers public Translation Get(string key) { this.ForLocale.TryGetValue(key, out Translation translation); - return translation ?? new Translation(this.ModName, this.Locale, key, null); + return translation ?? new Translation(this.Locale, key, null); } /// Get a translation for the current locale. @@ -105,7 +98,7 @@ namespace StardewModdingAPI.Framework.ModHelpers foreach (var pair in translations) { if (!this.ForLocale.ContainsKey(pair.Key)) - this.ForLocale.Add(pair.Key, new Translation(this.ModName, this.Locale, pair.Key, pair.Value)); + this.ForLocale.Add(pair.Key, new Translation(this.Locale, pair.Key, pair.Value)); } } } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index bc893abc..a4b38a50 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -960,7 +960,7 @@ namespace StardewModdingAPI.Framework IManifest manifest = mod.Manifest; IMonitor monitor = this.GetSecondaryMonitor(mod.DisplayName); IContentHelper contentHelper = new ContentHelper(this.ContentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, monitor); - TranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, manifest.Name, contentCore.GetLocale(), contentCore.Language); + TranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, contentCore.GetLocale(), contentCore.Language); IContentPack contentPack = new ContentPack(mod.DirectoryPath, manifest, contentHelper, translationHelper, jsonHelper); mod.SetMod(contentPack, monitor, translationHelper); this.ModRegistry.Add(mod); @@ -1024,7 +1024,7 @@ namespace StardewModdingAPI.Framework // init mod helpers IMonitor monitor = this.GetSecondaryMonitor(mod.DisplayName); - TranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, manifest.Name, contentCore.GetLocale(), contentCore.Language); + TranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, contentCore.GetLocale(), contentCore.Language); IModHelper modHelper; { IModEvents events = new ModEvents(mod, this.EventManager); @@ -1040,7 +1040,7 @@ namespace StardewModdingAPI.Framework { IMonitor packMonitor = this.GetSecondaryMonitor(packManifest.Name); IContentHelper packContentHelper = new ContentHelper(contentCore, packDirPath, packManifest.UniqueID, packManifest.Name, packMonitor); - ITranslationHelper packTranslationHelper = new TranslationHelper(packManifest.UniqueID, packManifest.Name, contentCore.GetLocale(), contentCore.Language); + ITranslationHelper packTranslationHelper = new TranslationHelper(packManifest.UniqueID, contentCore.GetLocale(), contentCore.Language); return new ContentPack(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper); } diff --git a/src/SMAPI/Translation.cs b/src/SMAPI/Translation.cs index e8698e2c..2196c8a5 100644 --- a/src/SMAPI/Translation.cs +++ b/src/SMAPI/Translation.cs @@ -15,9 +15,6 @@ namespace StardewModdingAPI /// The placeholder text when the translation is null or empty, where {0} is the translation key. internal const string PlaceholderText = "(no translation:{0})"; - /// The name of the relevant mod for error messages. - private readonly string ModName; - /// The locale for which the translation was fetched. private readonly string Locale; @@ -39,36 +36,11 @@ namespace StardewModdingAPI ** Public methods *********/ /// Construct an instance. - /// The name of the relevant mod for error messages. - /// The locale for which the translation was fetched. - /// The translation key. - /// The underlying translation text. - internal Translation(string modName, string locale, string key, string text) - : this(modName, locale, key, text, string.Format(Translation.PlaceholderText, key)) { } - - /// Construct an instance. - /// The name of the relevant mod for error messages. /// The locale for which the translation was fetched. /// The translation key. /// The underlying translation text. - /// The value to return if the translations is undefined. - internal Translation(string modName, string locale, string key, string text, string placeholder) - { - this.ModName = modName; - this.Locale = locale; - this.Key = key; - this.Text = text; - this.Placeholder = placeholder; - } - - /// Throw an exception if the translation text is null or empty. - /// There's no available translation matching the requested key and locale. - public Translation Assert() - { - if (!this.HasValue()) - throw new KeyNotFoundException($"The '{this.ModName}' mod doesn't have a translation with key '{this.Key}' for the '{this.Locale}' locale or its fallbacks."); - return this; - } + internal Translation(string locale, string key, string text) + : this(locale, key, text, string.Format(Translation.PlaceholderText, key)) { } /// Replace the text if it's null or empty. If you set a null or empty value, the translation will show the fallback "no translation" placeholder (see if you want to disable that). Returns a new instance if changed. /// The default value. @@ -76,14 +48,14 @@ namespace StardewModdingAPI { return this.HasValue() ? this - : new Translation(this.ModName, this.Locale, this.Key, @default); + : new Translation(this.Locale, this.Key, @default); } /// Whether to return a "no translation" placeholder if the translation is null or empty. Returns a new instance. /// Whether to return a placeholder. public Translation UsePlaceholder(bool use) { - return new Translation(this.ModName, this.Locale, this.Key, this.Text, use ? string.Format(Translation.PlaceholderText, this.Key) : null); + return new Translation(this.Locale, this.Key, this.Text, use ? string.Format(Translation.PlaceholderText, this.Key) : null); } /// Replace tokens in the text like {{value}} with the given values. Returns a new instance. @@ -127,7 +99,7 @@ namespace StardewModdingAPI ? value : match.Value; }); - return new Translation(this.ModName, this.Locale, this.Key, text); + return new Translation(this.Locale, this.Key, text); } /// Get whether the translation has a defined value. @@ -150,5 +122,22 @@ namespace StardewModdingAPI { return translation?.ToString(); } + + + /********* + ** Private methods + *********/ + /// Construct an instance. + /// The locale for which the translation was fetched. + /// The translation key. + /// The underlying translation text. + /// The value to return if the translations is undefined. + private Translation(string locale, string key, string text, string placeholder) + { + this.Locale = locale; + this.Key = key; + this.Text = text; + this.Placeholder = placeholder; + } } } -- cgit From 845deb43d60147603ec31fe4ae5fd7d747556d8c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 1 Oct 2019 21:27:49 -0400 Subject: add support for core translation files --- build/common.targets | 5 + build/prepare-install-package.targets | 4 + docs/README.md | 20 ++++ docs/release-notes.md | 5 + .../Framework/ModHelpers/TranslationHelper.cs | 78 ++----------- src/SMAPI/Framework/SCore.cs | 127 ++++++++++++-------- src/SMAPI/Framework/SGame.cs | 7 +- src/SMAPI/Framework/Translator.cs | 128 +++++++++++++++++++++ src/SMAPI/SMAPI.csproj | 3 + src/SMAPI/i18n/default.json | 3 + 10 files changed, 265 insertions(+), 115 deletions(-) create mode 100644 src/SMAPI/Framework/Translator.cs create mode 100644 src/SMAPI/i18n/default.json (limited to 'src/SMAPI') diff --git a/build/common.targets b/build/common.targets index eb92cddd..10cdbe2c 100644 --- a/build/common.targets +++ b/build/common.targets @@ -21,6 +21,10 @@ + + + + @@ -29,6 +33,7 @@ + diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index 18a69a24..e5286bf5 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -17,6 +17,9 @@ windows unix + + + @@ -46,6 +49,7 @@ + diff --git a/docs/README.md b/docs/README.md index 90204387..fdb60693 100644 --- a/docs/README.md +++ b/docs/README.md @@ -54,3 +54,23 @@ developers and other modders! ### For SMAPI developers * [Technical docs](technical/smapi.md) + +## Translating SMAPI +SMAPI rarely shows text in-game, so it only has a few translations. Contributions are welcome! See +[Modding:Translations](https://stardewvalleywiki.com/Modding:Translations) on the wiki for help +contributing translations. + +locale | status +---------- | :---------------- +default | ✓ [fully translated](../src/SMAPI/i18n/default.json) +Chinese | ❑ not translated +French | ❑ not translated +German | ❑ not translated +Hungarian | ❑ not translated +Italian | ❑ not translated +Japanese | ❑ not translated +Korean | ❑ not translated +Portuguese | ❑ not translated +Russian | ❑ not translated +Spanish | ❑ not translated +Turkish | ❑ not translated diff --git a/docs/release-notes.md b/docs/release-notes.md index 26645210..5d8253b4 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -113,6 +113,11 @@ For modders: * Fixed changes to `Data\NPCDispositions` not always propagated correctly to existing NPCs. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. +### For SMAPI maintainers +* Added support for core translation files. +* Migrated to new `.csproj` format. +* Internal refactoring. + ## 2.11.3 Released 13 September 2019 for Stardew Valley 1.3.36. diff --git a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs index 65850384..be7768e8 100644 --- a/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/TranslationHelper.cs @@ -1,6 +1,4 @@ -using System; using System.Collections.Generic; -using System.Linq; using StardewValley; namespace StardewModdingAPI.Framework.ModHelpers @@ -11,21 +9,18 @@ namespace StardewModdingAPI.Framework.ModHelpers /********* ** Fields *********/ - /// The translations for each locale. - private readonly IDictionary> All = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - - /// The translations for the current locale, with locale fallback taken into account. - private IDictionary ForLocale; + /// The underlying translation manager. + private readonly Translator Translator; /********* ** Accessors *********/ /// The current locale. - public string Locale { get; private set; } + public string Locale => this.Translator.Locale; /// The game's current language code. - public LocalizedContentManager.LanguageCode LocaleEnum { get; private set; } + public LocalizedContentManager.LanguageCode LocaleEnum => this.Translator.LocaleEnum; /********* @@ -38,22 +33,21 @@ namespace StardewModdingAPI.Framework.ModHelpers public TranslationHelper(string modID, string locale, LocalizedContentManager.LanguageCode languageCode) : base(modID) { - // set locale - this.SetLocale(locale, languageCode); + this.Translator = new Translator(); + this.Translator.SetLocale(locale, languageCode); } /// Get all translations for the current locale. public IEnumerable GetTranslations() { - return this.ForLocale.Values.ToArray(); + return this.Translator.GetTranslations(); } /// Get a translation for the current locale. /// The translation key. public Translation Get(string key) { - this.ForLocale.TryGetValue(key, out Translation translation); - return translation ?? new Translation(this.Locale, key, null); + return this.Translator.Get(key); } /// Get a translation for the current locale. @@ -61,21 +55,14 @@ namespace StardewModdingAPI.Framework.ModHelpers /// An object containing token key/value pairs. This can be an anonymous object (like new { value = 42, name = "Cranberries" }), a dictionary, or a class instance. public Translation Get(string key, object tokens) { - return this.Get(key).Tokens(tokens); + return this.Translator.Get(key, tokens); } /// Set the translations to use. /// The translations to use. internal TranslationHelper SetTranslations(IDictionary> translations) { - // reset translations - this.All.Clear(); - foreach (var pair in translations) - this.All[pair.Key] = new Dictionary(pair.Value, StringComparer.InvariantCultureIgnoreCase); - - // rebuild cache - this.SetLocale(this.Locale, this.LocaleEnum); - + this.Translator.SetTranslations(translations); return this; } @@ -84,50 +71,7 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The game's current language code. internal void SetLocale(string locale, LocalizedContentManager.LanguageCode localeEnum) { - this.Locale = locale.ToLower().Trim(); - this.LocaleEnum = localeEnum; - - this.ForLocale = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - foreach (string next in this.GetRelevantLocales(this.Locale)) - { - // skip if locale not defined - if (!this.All.TryGetValue(next, out IDictionary translations)) - continue; - - // add missing translations - foreach (var pair in translations) - { - if (!this.ForLocale.ContainsKey(pair.Key)) - this.ForLocale.Add(pair.Key, new Translation(this.Locale, pair.Key, pair.Value)); - } - } - } - - - /********* - ** Private methods - *********/ - /// Get the locales which can provide translations for the given locale, in precedence order. - /// The locale for which to find valid locales. - private IEnumerable GetRelevantLocales(string locale) - { - // given locale - yield return locale; - - // broader locales (like pt-BR => pt) - while (true) - { - int dashIndex = locale.LastIndexOf('-'); - if (dashIndex <= 0) - break; - - locale = locale.Substring(0, dashIndex); - yield return locale; - } - - // default - if (locale != "default") - yield return "default"; + this.Translator.SetLocale(locale, localeEnum); } } } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index a4b38a50..bd131762 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -61,6 +61,9 @@ namespace StardewModdingAPI.Framework /// Simplifies access to private game code. private readonly Reflector Reflection = new Reflector(); + /// Encapsulates access to SMAPI core translations. + private readonly Translator Translator = new Translator(); + /// The SMAPI configuration settings. private readonly SConfig Settings; @@ -223,6 +226,7 @@ namespace StardewModdingAPI.Framework monitor: this.Monitor, monitorForGame: this.MonitorForGame, reflection: this.Reflection, + translator: this.Translator, eventManager: this.EventManager, jsonHelper: this.Toolkit.JsonHelper, modRegistry: this.ModRegistry, @@ -232,6 +236,7 @@ namespace StardewModdingAPI.Framework cancellationToken: this.CancellationToken, logNetworkTraffic: this.Settings.LogNetworkTraffic ); + this.Translator.SetLocale(this.GameInstance.ContentCore.GetLocale(), this.GameInstance.ContentCore.Language); StardewValley.Program.gamePtr = this.GameInstance; // apply game patches @@ -466,6 +471,9 @@ namespace StardewModdingAPI.Framework string locale = this.ContentCore.GetLocale(); LocalizedContentManager.LanguageCode languageCode = this.ContentCore.Language; + // update core translations + this.Translator.SetLocale(locale, languageCode); + // update mod translation helpers foreach (IModMetadata mod in this.ModRegistry.GetAll()) mod.Translations.SetLocale(locale, languageCode); @@ -1027,6 +1035,14 @@ namespace StardewModdingAPI.Framework TranslationHelper translationHelper = new TranslationHelper(manifest.UniqueID, contentCore.GetLocale(), contentCore.Language); IModHelper modHelper; { + IContentPack CreateFakeContentPack(string packDirPath, IManifest packManifest) + { + IMonitor packMonitor = this.GetSecondaryMonitor(packManifest.Name); + IContentHelper packContentHelper = new ContentHelper(contentCore, packDirPath, packManifest.UniqueID, packManifest.Name, packMonitor); + ITranslationHelper packTranslationHelper = new TranslationHelper(packManifest.UniqueID, contentCore.GetLocale(), contentCore.Language); + return new ContentPack(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper); + } + IModEvents events = new ModEvents(mod, this.EventManager); ICommandHelper commandHelper = new CommandHelper(mod, this.GameInstance.CommandManager); IContentHelper contentHelper = new ContentHelper(contentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, monitor); @@ -1036,14 +1052,6 @@ namespace StardewModdingAPI.Framework IModRegistry modRegistryHelper = new ModRegistryHelper(manifest.UniqueID, this.ModRegistry, proxyFactory, monitor); IMultiplayerHelper multiplayerHelper = new MultiplayerHelper(manifest.UniqueID, this.GameInstance.Multiplayer); - IContentPack CreateFakeContentPack(string packDirPath, IManifest packManifest) - { - IMonitor packMonitor = this.GetSecondaryMonitor(packManifest.Name); - IContentHelper packContentHelper = new ContentHelper(contentCore, packDirPath, packManifest.UniqueID, packManifest.Name, packMonitor); - ITranslationHelper packTranslationHelper = new TranslationHelper(packManifest.UniqueID, contentCore.GetLocale(), contentCore.Language); - return new ContentPack(packDirPath, packManifest, packContentHelper, packTranslationHelper, this.Toolkit.JsonHelper); - } - modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.GameInstance.Input, events, contentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper); } @@ -1205,60 +1213,85 @@ namespace StardewModdingAPI.Framework /// The mods for which to reload translations. private void ReloadTranslations(IEnumerable mods) { - JsonHelper jsonHelper = this.Toolkit.JsonHelper; + // core SMAPI translations + { + var translations = this.ReadTranslationFiles(Path.Combine(Constants.InternalFilesPath, "i18n"), out IList errors); + if (errors.Any() || !translations.Any()) + { + this.Monitor.Log("SMAPI couldn't load some core translations. You may need to reinstall SMAPI.", LogLevel.Warn); + foreach (string error in errors) + this.Monitor.Log($" - {error}", LogLevel.Warn); + } + this.Translator.SetTranslations(translations); + } + + // mod translations foreach (IModMetadata metadata in mods) { - // read translation files - IDictionary> translations = new Dictionary>(); - DirectoryInfo translationsDir = new DirectoryInfo(Path.Combine(metadata.DirectoryPath, "i18n")); - if (translationsDir.Exists) + var translations = this.ReadTranslationFiles(Path.Combine(metadata.DirectoryPath, "i18n"), out IList errors); + if (errors.Any()) { - foreach (FileInfo file in translationsDir.EnumerateFiles("*.json")) + metadata.LogAsMod("Mod couldn't load some translation files:", LogLevel.Warn); + foreach (string error in errors) + metadata.LogAsMod($" - {error}", LogLevel.Warn); + } + metadata.Translations.SetTranslations(translations); + } + } + + /// Read translations from a directory containing JSON translation files. + /// The folder path to search. + /// The errors indicating why translation files couldn't be parsed, indexed by translation filename. + private IDictionary> ReadTranslationFiles(string folderPath, out IList errors) + { + JsonHelper jsonHelper = this.Toolkit.JsonHelper; + + // read translation files + var translations = new Dictionary>(); + errors = new List(); + DirectoryInfo translationsDir = new DirectoryInfo(folderPath); + if (translationsDir.Exists) + { + foreach (FileInfo file in translationsDir.EnumerateFiles("*.json")) + { + string locale = Path.GetFileNameWithoutExtension(file.Name.ToLower().Trim()); + try { - string locale = Path.GetFileNameWithoutExtension(file.Name.ToLower().Trim()); - try - { - if (jsonHelper.ReadJsonFileIfExists(file.FullName, out IDictionary data)) - translations[locale] = data; - else - metadata.LogAsMod($"Mod's i18n/{locale}.json file couldn't be parsed.", LogLevel.Warn); - } - catch (Exception ex) + if (!jsonHelper.ReadJsonFileIfExists(file.FullName, out IDictionary data)) { - metadata.LogAsMod($"Mod's i18n/{locale}.json file couldn't be parsed: {ex.GetLogSummary()}", LogLevel.Warn); + errors.Add($"{file.Name} file couldn't be read"); // should never happen, since we're iterating files that exist + continue; } - } - } - // validate translations - foreach (string locale in translations.Keys.ToArray()) - { - // skip empty files - if (translations[locale] == null || !translations[locale].Keys.Any()) + translations[locale] = data; + } + catch (Exception ex) { - metadata.LogAsMod($"Mod's i18n/{locale}.json is empty and will be ignored.", LogLevel.Warn); - translations.Remove(locale); + errors.Add($"{file.Name} file couldn't be parsed: {ex.GetLogSummary()}"); continue; } + } + } - // handle duplicates - HashSet keys = new HashSet(StringComparer.InvariantCultureIgnoreCase); - HashSet duplicateKeys = new HashSet(StringComparer.InvariantCultureIgnoreCase); - foreach (string key in translations[locale].Keys.ToArray()) + // validate translations + foreach (string locale in translations.Keys.ToArray()) + { + // handle duplicates + HashSet keys = new HashSet(StringComparer.InvariantCultureIgnoreCase); + HashSet duplicateKeys = new HashSet(StringComparer.InvariantCultureIgnoreCase); + foreach (string key in translations[locale].Keys.ToArray()) + { + if (!keys.Add(key)) { - if (!keys.Add(key)) - { - duplicateKeys.Add(key); - translations[locale].Remove(key); - } + duplicateKeys.Add(key); + translations[locale].Remove(key); } - if (duplicateKeys.Any()) - metadata.LogAsMod($"Mod's i18n/{locale}.json has duplicate translation keys: [{string.Join(", ", duplicateKeys)}]. Keys are case-insensitive.", LogLevel.Warn); } - - // update translation - metadata.Translations.SetTranslations(translations); + if (duplicateKeys.Any()) + errors.Add($"{locale}.json has duplicate translation keys: [{string.Join(", ", duplicateKeys)}]. Keys are case-insensitive."); } + + return translations; } /// The method called when the user submits a core SMAPI command in the console. diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index cb1b9be5..89705352 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -83,6 +83,9 @@ namespace StardewModdingAPI.Framework /// Simplifies access to private game code. private readonly Reflector Reflection; + /// Encapsulates access to SMAPI core translations. + private readonly Translator Translator; + /// Propagates notification that SMAPI should exit. private readonly CancellationTokenSource CancellationToken; @@ -135,6 +138,7 @@ namespace StardewModdingAPI.Framework /// Encapsulates monitoring and logging for SMAPI. /// Encapsulates monitoring and logging on the game's behalf. /// Simplifies access to private game code. + /// Encapsulates access to arbitrary translations. /// Manages SMAPI events for mods. /// Encapsulates SMAPI's JSON file parsing. /// Tracks the installed mods. @@ -143,7 +147,7 @@ namespace StardewModdingAPI.Framework /// A callback to invoke when the game exits. /// Propagates notification that SMAPI should exit. /// Whether to log network traffic. - internal SGame(Monitor monitor, IMonitor monitorForGame, Reflector reflection, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialized, Action onGameExiting, CancellationTokenSource cancellationToken, bool logNetworkTraffic) + internal SGame(Monitor monitor, IMonitor monitorForGame, Reflector reflection, Translator translator, EventManager eventManager, JsonHelper jsonHelper, ModRegistry modRegistry, DeprecationManager deprecationManager, Action onGameInitialized, Action onGameExiting, CancellationTokenSource cancellationToken, bool logNetworkTraffic) { this.OnLoadingFirstAsset = SGame.ConstructorHack.OnLoadingFirstAsset; SGame.ConstructorHack = null; @@ -161,6 +165,7 @@ namespace StardewModdingAPI.Framework this.Events = eventManager; this.ModRegistry = modRegistry; this.Reflection = reflection; + this.Translator = translator; this.DeprecationManager = deprecationManager; this.OnGameInitialized = onGameInitialized; this.OnGameExiting = onGameExiting; diff --git a/src/SMAPI/Framework/Translator.cs b/src/SMAPI/Framework/Translator.cs new file mode 100644 index 00000000..f2738633 --- /dev/null +++ b/src/SMAPI/Framework/Translator.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Framework +{ + /// Encapsulates access to arbitrary translations. Translations are fetched with locale fallback, so missing translations are filled in from broader locales (like pt-BR.json < pt.json < default.json). + internal class Translator + { + /********* + ** Fields + *********/ + /// The translations for each locale. + private readonly IDictionary> All = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); + + /// The translations for the current locale, with locale fallback taken into account. + private IDictionary ForLocale; + + + /********* + ** Accessors + *********/ + /// The current locale. + public string Locale { get; private set; } + + /// The game's current language code. + public LocalizedContentManager.LanguageCode LocaleEnum { get; private set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public Translator() + { + this.SetLocale(string.Empty, LocalizedContentManager.LanguageCode.en); + } + + /// Set the current locale and precache translations. + /// The current locale. + /// The game's current language code. + public void SetLocale(string locale, LocalizedContentManager.LanguageCode localeEnum) + { + this.Locale = locale.ToLower().Trim(); + this.LocaleEnum = localeEnum; + + this.ForLocale = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (string next in this.GetRelevantLocales(this.Locale)) + { + // skip if locale not defined + if (!this.All.TryGetValue(next, out IDictionary translations)) + continue; + + // add missing translations + foreach (var pair in translations) + { + if (!this.ForLocale.ContainsKey(pair.Key)) + this.ForLocale.Add(pair.Key, new Translation(this.Locale, pair.Key, pair.Value)); + } + } + } + + /// Get all translations for the current locale. + public IEnumerable GetTranslations() + { + return this.ForLocale.Values.ToArray(); + } + + /// Get a translation for the current locale. + /// The translation key. + public Translation Get(string key) + { + this.ForLocale.TryGetValue(key, out Translation translation); + return translation ?? new Translation(this.Locale, key, null); + } + + /// Get a translation for the current locale. + /// The translation key. + /// An object containing token key/value pairs. This can be an anonymous object (like new { value = 42, name = "Cranberries" }), a dictionary, or a class instance. + public Translation Get(string key, object tokens) + { + return this.Get(key).Tokens(tokens); + } + + /// Set the translations to use. + /// The translations to use. + internal Translator SetTranslations(IDictionary> translations) + { + // reset translations + this.All.Clear(); + foreach (var pair in translations) + this.All[pair.Key] = new Dictionary(pair.Value, StringComparer.InvariantCultureIgnoreCase); + + // rebuild cache + this.SetLocale(this.Locale, this.LocaleEnum); + + return this; + } + + + /********* + ** Private methods + *********/ + /// Get the locales which can provide translations for the given locale, in precedence order. + /// The locale for which to find valid locales. + private IEnumerable GetRelevantLocales(string locale) + { + // given locale + yield return locale; + + // broader locales (like pt-BR => pt) + while (true) + { + int dashIndex = locale.LastIndexOf('-'); + if (dashIndex <= 0) + break; + + locale = locale.Substring(0, dashIndex); + yield return locale; + } + + // default + if (locale != "default") + yield return "default"; + } + } +} diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 7c7bfc71..62002a40 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -99,6 +99,9 @@ SMAPI.metadata.json PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/src/SMAPI/i18n/default.json b/src/SMAPI/i18n/default.json new file mode 100644 index 00000000..0db3279e --- /dev/null +++ b/src/SMAPI/i18n/default.json @@ -0,0 +1,3 @@ +{ + +} -- cgit From 65997c1243a60ae15cc0b832ebcd41d96c3ea06a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 1 Oct 2019 21:41:15 -0400 Subject: auto-fix save data when a custom location mod is removed --- docs/README.md | 6 +++--- docs/release-notes.md | 4 ++-- src/SMAPI/Framework/SCore.cs | 2 +- src/SMAPI/Framework/SGame.cs | 19 +++++++++++++++++++ src/SMAPI/Patches/LoadErrorPatch.cs | 28 +++++++++++++++++++++++++++- src/SMAPI/i18n/default.json | 2 +- 6 files changed, 53 insertions(+), 8 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/README.md b/docs/README.md index fdb60693..54e9f26f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,10 +23,10 @@ doesn't change any of your game files. It serves eight main purposes: _SMAPI intercepts errors, shows the error info in the SMAPI console, and in most cases automatically recovers the game. That prevents mods from crashing the game, and makes it possible to troubleshoot errors in the game itself that would otherwise show a generic 'program - has stopped working' type of message._ + has stopped working' type of message._ - _That also includes automatically fixing save data when a load would crash, e.g. due to a custom - NPC mod the player removed._ + _SMAPI also automatically fixes save data in some cases when a load would crash, e.g. due to a + custom location or NPC mod that was removed._ 6. **Provide update checks.** _SMAPI automatically checks for new versions of your installed mods, and notifies you when any diff --git a/docs/release-notes.md b/docs/release-notes.md index 5d8253b4..41a98dbe 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -13,7 +13,7 @@ For players: SMAPI should have less impact on game performance and startup time for some players. * **Added more error recovery.** - SMAPI now detects and prevents more crashes due to game or mod bugs, or due to removing some mods which add custom content. + SMAPI now detects and prevents more crashes due to game/mod bugs, or due to removing mods which add custom locations or NPCs. * **Improved mod scanning.** SMAPI now supports some non-standard mod structures automatically, improves compatibility with the Vortex mod manager, and improves various error/skip messages related to mod loading. @@ -46,7 +46,7 @@ For modders: * Improved mod scanning: * Now ignores metadata files and folders (like `__MACOSX` and `__folder_managed_by_vortex`) and content files (like `.txt` or `.png`), which avoids missing-manifest errors in some common cases. * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages. - * SMAPI now automatically fixes your save if you remove a custom NPC mod. (Invalid NPCs are now removed on load, with a warning in the console.) + * SMAPI now automatically removes invalid content when loading a save to prevent crashes. A warning is shown in-game when this happens. This applies for locations and NPCs. * Added support for configuring console colors via `smapi-internal/config.json` (intended for players with unusual consoles). * Improved launch script compatibility on Linux (thanks to kurumushi and toastal!). * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index bd131762..bfdf1c51 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -245,7 +245,7 @@ namespace StardewModdingAPI.Framework new DialogueErrorPatch(this.MonitorForGame, this.Reflection), new ObjectErrorPatch(), new LoadContextPatch(this.Reflection, this.GameInstance.OnLoadStageChanged), - new LoadErrorPatch(this.Monitor) + new LoadErrorPatch(this.Monitor, this.GameInstance.OnSaveContentRemoved) ); // add exit handler diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 89705352..13858fc5 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -65,6 +65,9 @@ namespace StardewModdingAPI.Framework /// Skipping a few frames ensures the game finishes initializing the world before mods try to change it. private readonly Countdown AfterLoadTimer = new Countdown(5); + /// Whether custom content was removed from the save data to avoid a crash. + private bool IsSaveContentRemoved; + /// Whether the game is saving and SMAPI has already raised . private bool IsBetweenSaveEvents; @@ -216,6 +219,12 @@ namespace StardewModdingAPI.Framework this.Events.ModMessageReceived.RaiseForMods(new ModMessageReceivedEventArgs(message), mod => mod != null && modIDs.Contains(mod.Manifest.UniqueID)); } + /// A callback invoked when custom content is removed from the save data to avoid a crash. + internal void OnSaveContentRemoved() + { + this.IsSaveContentRemoved = true; + } + /// A callback invoked when the game's low-level load stage changes. /// The new load stage. internal void OnLoadStageChanged(LoadStage newStage) @@ -457,6 +466,16 @@ namespace StardewModdingAPI.Framework this.Watchers.Reset(); WatcherSnapshot state = this.WatcherSnapshot; + /********* + ** Display in-game warnings + *********/ + // save content removed + if (this.IsSaveContentRemoved && Context.IsWorldReady) + { + this.IsSaveContentRemoved = false; + Game1.addHUDMessage(new HUDMessage(this.Translator.Get("warn.invalid-content-removed"), HUDMessage.error_type)); + } + /********* ** Pre-update events *********/ diff --git a/src/SMAPI/Patches/LoadErrorPatch.cs b/src/SMAPI/Patches/LoadErrorPatch.cs index 87e8ee14..eedb4164 100644 --- a/src/SMAPI/Patches/LoadErrorPatch.cs +++ b/src/SMAPI/Patches/LoadErrorPatch.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -20,6 +21,9 @@ namespace StardewModdingAPI.Patches /// Writes messages to the console and log file. private static IMonitor Monitor; + /// A callback invoked when custom content is removed from the save data to avoid a crash. + private static Action OnContentRemoved; + /********* ** Accessors @@ -33,9 +37,11 @@ namespace StardewModdingAPI.Patches *********/ /// Construct an instance. /// Writes messages to the console and log file. - public LoadErrorPatch(IMonitor monitor) + /// A callback invoked when custom content is removed from the save data to avoid a crash. + public LoadErrorPatch(IMonitor monitor, Action onContentRemoved) { LoadErrorPatch.Monitor = monitor; + LoadErrorPatch.OnContentRemoved = onContentRemoved; } @@ -58,6 +64,22 @@ namespace StardewModdingAPI.Patches /// Returns whether to execute the original method. private static bool Before_SaveGame_LoadDataToLocations(List gamelocations) { + bool removedAny = false; + + // remove invalid locations + foreach (GameLocation location in gamelocations.ToArray()) + { + if (location is Cellar) + continue; // missing cellars will be added by the game code + + if (Game1.getLocationFromName(location.name) == null) + { + LoadErrorPatch.Monitor.Log($"Removed invalid location '{location.Name}' to avoid a crash when loading save '{Constants.SaveFolderName}'. (Did you remove a custom location mod?)", LogLevel.Warn); + gamelocations.Remove(location); + removedAny = true; + } + } + // get building interiors var interiors = ( @@ -83,11 +105,15 @@ namespace StardewModdingAPI.Patches { LoadErrorPatch.Monitor.Log($"Removed invalid villager '{npc.Name}' to avoid a crash when loading save '{Constants.SaveFolderName}'. (Did you remove a custom NPC mod?)", LogLevel.Warn); location.characters.Remove(npc); + removedAny = true; } } } } + if (removedAny) + LoadErrorPatch.OnContentRemoved(); + return true; } } diff --git a/src/SMAPI/i18n/default.json b/src/SMAPI/i18n/default.json index 0db3279e..5a3e4a6e 100644 --- a/src/SMAPI/i18n/default.json +++ b/src/SMAPI/i18n/default.json @@ -1,3 +1,3 @@ { - + "warn.invalid-content-removed": "Invalid content was removed to prevent a crash (see the SMAPI console for info)." } -- cgit From 15cd316ce44fb1ca43b29f6087243cc3af2f78fb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 2 Oct 2019 01:19:33 -0400 Subject: fix Save Backup mod on Android --- src/SMAPI.Mods.SaveBackup/ModEntry.cs | 1 + src/SMAPI/Constants.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI.Mods.SaveBackup/ModEntry.cs b/src/SMAPI.Mods.SaveBackup/ModEntry.cs index 845df453..efc6f39f 100644 --- a/src/SMAPI.Mods.SaveBackup/ModEntry.cs +++ b/src/SMAPI.Mods.SaveBackup/ModEntry.cs @@ -73,6 +73,7 @@ namespace StardewModdingAPI.Mods.SaveBackup this.Monitor.Log($"Backing up saves to {targetFile.FullName}...", LogLevel.Trace); switch (Constants.TargetPlatform) { + case GamePlatform.Android: case GamePlatform.Linux: case GamePlatform.Windows: { diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index e3a6e6d5..9b113733 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -190,7 +190,7 @@ namespace StardewModdingAPI ** Private methods *********/ /// Get the name of the save folder, if any. - internal static string GetSaveFolderName() + private static string GetSaveFolderName() { // save not available if (Context.LoadStage == LoadStage.None) @@ -215,7 +215,7 @@ namespace StardewModdingAPI } /// Get the path to the current save folder, if any. - internal static string GetSaveFolderPathIfExists() + private static string GetSaveFolderPathIfExists() { string folderName = Constants.GetSaveFolderName(); if (folderName == null) -- cgit From 175ebf907134e1e32992f62637a5d7e43bfc6a20 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 3 Oct 2019 12:08:22 -0400 Subject: fix non-generic GetAPI not checking that all mods are loaded (#662) --- docs/release-notes.md | 1 + .../Framework/ModHelpers/ModRegistryHelper.cs | 24 ++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 30a759be..9cfb70a6 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -112,6 +112,7 @@ For modders: * Fixed asset propagation for NPC portraits resetting any unique portraits (e.g. Maru's hospital portrait) to the default. * Fixed changes to `Data\NPCDispositions` not always propagated correctly to existing NPCs. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. + * Fixed `GetApi` without an interface not checking if all mods are loaded. ### For SMAPI maintainers * Added support for core translation files. diff --git a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs index 24bed3bb..f42cb085 100644 --- a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using StardewModdingAPI.Framework.Reflection; namespace StardewModdingAPI.Framework.ModHelpers @@ -63,6 +62,14 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Get the API provided by a mod, or null if it has none. This signature requires using the API to access the API's properties and methods. public object GetApi(string uniqueID) { + // validate ready + if (!this.Registry.AreAllModsInitialized) + { + this.Monitor.Log("Tried to access a mod-provided API before all mods were initialized.", LogLevel.Error); + return null; + } + + // get raw API IModMetadata mod = this.Registry.Get(uniqueID); if (mod?.Api != null && this.AccessedModApis.Add(mod.Manifest.UniqueID)) this.Monitor.Log($"Accessed mod-provided API for {mod.DisplayName}.", LogLevel.Trace); @@ -74,12 +81,12 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The mod's unique ID. public TInterface GetApi(string uniqueID) where TInterface : class { - // validate - if (!this.Registry.AreAllModsInitialized) - { - this.Monitor.Log("Tried to access a mod-provided API before all mods were initialized.", LogLevel.Error); + // get raw API + object api = this.GetApi(uniqueID); + if (api == null) return null; - } + + // validate mapping if (!typeof(TInterface).IsInterface) { this.Monitor.Log($"Tried to map a mod-provided API to class '{typeof(TInterface).FullName}'; must be a public interface.", LogLevel.Error); @@ -91,11 +98,6 @@ namespace StardewModdingAPI.Framework.ModHelpers return null; } - // get raw API - object api = this.GetApi(uniqueID); - if (api == null) - return null; - // get API of type if (api is TInterface castApi) return castApi; -- cgit From 08dc846195df5609e5c9f07ed828d9789176d93e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 22 Oct 2019 07:59:20 -0400 Subject: add asset propagation for cursors2 (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index fceb840f..14ce5aaa 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -303,6 +303,10 @@ namespace StardewModdingAPI.Metadata } return true; + case "loosesprites\\cursors2": // Game1.LoadContent + Game1.mouseCursors2 = content.Load(key); + return true; + case "loosesprites\\daybg": // Game1.LoadContent Game1.daybg = content.Load(key); return true; -- cgit From f4bc61976c1d16b9c011217c8347912cb535dc71 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 29 Oct 2019 11:29:20 -0400 Subject: update for networking changes in SDV 1.4 (#638) --- src/SMAPI/Framework/Networking/SGalaxyNetServer.cs | 2 +- src/SMAPI/Framework/Networking/SLidgrenServer.cs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs index bb67f70e..7dbfa767 100644 --- a/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs +++ b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs @@ -58,7 +58,7 @@ namespace StardewModdingAPI.Framework.Networking { NetFarmerRoot farmer = this.Multiplayer.readFarmer(message.Reader); GalaxyID capturedPeer = new GalaxyID(peerID); - this.gameServer.checkFarmhandRequest(Convert.ToString(peerID), farmer, msg => this.sendMessage(capturedPeer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = capturedPeer.ToUint64()); + this.gameServer.checkFarmhandRequest(Convert.ToString(peerID), this.getConnectionId(peer), farmer, msg => this.sendMessage(capturedPeer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = capturedPeer.ToUint64()); } }); } diff --git a/src/SMAPI/Framework/Networking/SLidgrenServer.cs b/src/SMAPI/Framework/Networking/SLidgrenServer.cs index 1bce47fe..d2fec146 100644 --- a/src/SMAPI/Framework/Networking/SLidgrenServer.cs +++ b/src/SMAPI/Framework/Networking/SLidgrenServer.cs @@ -33,6 +33,10 @@ namespace StardewModdingAPI.Framework.Networking this.OnProcessingMessage = onProcessingMessage; } + + /********* + ** Protected methods + *********/ /// Parse a data message from a client. /// The raw network message to parse. [SuppressMessage("ReSharper", "AccessToDisposedClosure", Justification = "The callback is invoked synchronously.")] @@ -55,11 +59,19 @@ namespace StardewModdingAPI.Framework.Networking else if (message.MessageType == StardewValley.Multiplayer.playerIntroduction) { NetFarmerRoot farmer = this.Multiplayer.readFarmer(message.Reader); - this.gameServer.checkFarmhandRequest("", farmer, msg => this.sendMessage(peer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = peer); + this.gameServer.checkFarmhandRequest("", this.getConnectionId(rawMessage.SenderConnection), farmer, msg => this.sendMessage(peer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = peer); } }); } } } + + /// Get the connection ID for a connection. + /// The connection. + /// Derived from the private method. + private string getConnectionId(NetConnection connection) + { + return $"L_{connection.RemoteUniqueIdentifier}"; + } } } -- cgit From 9035d945f9097bef363f4f7a658846423ecefd9b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 29 Oct 2019 16:41:24 -0400 Subject: update for further networking changes in SDV 1.4 (#638) --- src/SMAPI/Framework/Networking/SLidgrenServer.cs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/Networking/SLidgrenServer.cs b/src/SMAPI/Framework/Networking/SLidgrenServer.cs index d2fec146..f2c61917 100644 --- a/src/SMAPI/Framework/Networking/SLidgrenServer.cs +++ b/src/SMAPI/Framework/Networking/SLidgrenServer.cs @@ -65,13 +65,5 @@ namespace StardewModdingAPI.Framework.Networking } } } - - /// Get the connection ID for a connection. - /// The connection. - /// Derived from the private method. - private string getConnectionId(NetConnection connection) - { - return $"L_{connection.RemoteUniqueIdentifier}"; - } } } -- cgit From 8968d2737d1412dba31d797be9a6d85e93332480 Mon Sep 17 00:00:00 2001 From: Eren Kemer Date: Sat, 2 Nov 2019 13:02:13 +0100 Subject: Create de.json Translation into german, --- src/SMAPI/i18n/de.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/SMAPI/i18n/de.json (limited to 'src/SMAPI') diff --git a/src/SMAPI/i18n/de.json b/src/SMAPI/i18n/de.json new file mode 100644 index 00000000..a8b3086f --- /dev/null +++ b/src/SMAPI/i18n/de.json @@ -0,0 +1,3 @@ +{ + "warn.invalid-content-removed": "Ungültiger Inhalt wurde entfernt, um einen Absturz zu verhindern (siehe SMAPI Konsole für weitere Informationen)." +} -- cgit From df7e814286641c27a64cf354c15d69ddcfae062d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 3 Nov 2019 18:24:34 -0500 Subject: add support for using environment variables instead of command-line arguments (#665) --- docs/release-notes.md | 1 + docs/technical/smapi.md | 15 +++++++++++++-- src/SMAPI/Program.cs | 28 +++++++++++++++++----------- 3 files changed, 31 insertions(+), 13 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index b31950ed..47e12f83 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -48,6 +48,7 @@ For modders: * Now detects XNB mods more accurately, and consolidates multi-folder XNB mods in logged messages. * SMAPI now automatically removes invalid content when loading a save to prevent crashes. A warning is shown in-game when this happens. This applies for locations and NPCs. * Added support for configuring console colors via `smapi-internal/config.json` (intended for players with unusual consoles). + * Added support for specifying SMAPI command-line arguments as environment variables for Linux/Mac compatibility. * Improved launch script compatibility on Linux (thanks to kurumushi and toastal!). * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. * The installer now recognises custom game paths stored in `stardewvalley.targets`. diff --git a/docs/technical/smapi.md b/docs/technical/smapi.md index f6994ba3..96f7dff5 100644 --- a/docs/technical/smapi.md +++ b/docs/technical/smapi.md @@ -40,14 +40,25 @@ argument | purpose `--uninstall` | Preselects the uninstall action, skipping the prompt asking what the user wants to do. `--game-path "path"` | Specifies the full path to the folder containing the Stardew Valley executable, skipping automatic detection and any prompt to choose a path. If the path is not valid, the installer displays an error. -SMAPI itself recognises two arguments, but these are intended for internal use or testing and may -change without warning. +SMAPI itself recognises two arguments **on Windows only**, but these are intended for internal use +or testing and may change without warning. On Linux/Mac, see _environment variables_ below. argument | purpose -------- | ------- `--no-terminal` | SMAPI won't write anything to the console window. (Messages will still be written to the log file.) `--mods-path` | The path to search for mods, if not the standard `Mods` folder. This can be a path relative to the game folder (like `--mods-path "Mods (test)"`) or an absolute path. +### Environment variables +The above SMAPI arguments don't work on Linux/Mac due to the way the game launcher works. You can +set temporary environment variables instead. For example: +> SMAPI_MODS_PATH="Mods (multiplayer)" /path/to/StardewValley + +environment variable | purpose +-------------------- | ------- +`SMAPI_NO_TERMINAL` | Equivalent to `--no-terminal` above. +`SMAPI_MODS_PATH` | Equivalent to `--mods-path` above. + + ### Compile flags SMAPI uses a small number of conditional compilation constants, which you can set by editing the `` element in `SMAPI.csproj`. Supported constants: diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 2d143439..05d7ff66 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -116,21 +116,27 @@ namespace StardewModdingAPI /// This method is separate from because that can't contain any references to assemblies loaded by (e.g. via ), or Mono will incorrectly show an assembly resolution error before assembly resolution is set up. private static void Start(string[] args) { - // get flags from arguments - bool writeToConsole = !args.Contains("--no-terminal"); + // get flags + bool writeToConsole = !args.Contains("--no-terminal") && Environment.GetEnvironmentVariable("SMAPI_NO_TERMINAL") == null; - // get mods path from arguments - string modsPath = null; + // get mods path + string modsPath; { + string rawModsPath = null; + + // get from command line args int pathIndex = Array.LastIndexOf(args, "--mods-path") + 1; if (pathIndex >= 1 && args.Length >= pathIndex) - { - modsPath = args[pathIndex]; - if (!string.IsNullOrWhiteSpace(modsPath) && !Path.IsPathRooted(modsPath)) - modsPath = Path.Combine(Constants.ExecutionPath, modsPath); - } - if (string.IsNullOrWhiteSpace(modsPath)) - modsPath = Constants.DefaultModsPath; + rawModsPath = args[pathIndex]; + + // get from environment variables + if (string.IsNullOrWhiteSpace(rawModsPath)) + rawModsPath = Environment.GetEnvironmentVariable("SMAPI_MODS_PATH"); + + // normalise + modsPath = !string.IsNullOrWhiteSpace(rawModsPath) + ? Path.Combine(Constants.ExecutionPath, rawModsPath) + : Constants.DefaultModsPath; } // load SMAPI -- cgit From e454de1e11fd76130f373362ea38e224b1fcfaef Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 4 Nov 2019 12:02:29 -0500 Subject: remove obsolete validation Players can no longer launch SMAPI from the installer folder, since the files are hidden in a data file. --- src/SMAPI/Program.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 05d7ff66..d6e0888b 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -80,16 +80,7 @@ namespace StardewModdingAPI Platform platform = EnvironmentUtility.DetectPlatform(); string gameAssemblyName = platform == Platform.Windows ? "Stardew Valley" : "StardewValley"; if (Type.GetType($"StardewValley.Game1, {gameAssemblyName}", throwOnError: false) == null) - { - Program.PrintErrorAndExit( - "Oops! SMAPI can't find the game. " - + (Assembly.GetCallingAssembly().Location.Contains(Path.Combine("internal", "Windows")) || Assembly.GetCallingAssembly().Location.Contains(Path.Combine("internal", "Mono")) - ? "It looks like you're running SMAPI from the download package, but you need to run the installed version instead. " - : "Make sure you're running StardewModdingAPI.exe in your game folder. " - ) - + "See the readme.txt file for details." - ); - } + Program.PrintErrorAndExit("Oops! SMAPI can't find the game. Make sure you're running StardewModdingAPI.exe in your game folder. See the readme.txt file for details."); } /// Assert that the game version is within and . -- cgit From 01c612bc4aca5a1d8921432c94956f4d170d4d4b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 4 Nov 2019 13:59:34 -0500 Subject: add friendly error for BadImageFormatException on launch --- docs/release-notes.md | 1 + src/SMAPI/Program.cs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 47e12f83..7cd7b52b 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -50,6 +50,7 @@ For modders: * Added support for configuring console colors via `smapi-internal/config.json` (intended for players with unusual consoles). * Added support for specifying SMAPI command-line arguments as environment variables for Linux/Mac compatibility. * Improved launch script compatibility on Linux (thanks to kurumushi and toastal!). + * Made error messages more user-friendly in some cases. * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. * The installer now recognises custom game paths stored in `stardewvalley.targets`. * Duplicate-mod errors now show the mod version in each folder. diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index d6e0888b..6bacf564 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -40,6 +40,11 @@ namespace StardewModdingAPI Program.AssertGameVersion(); Program.Start(args); } + catch (BadImageFormatException ex) when (ex.FileName == "StardewValley") + { + string executableName = Program.GetExecutableAssemblyName(); + Console.WriteLine($"SMAPI failed to initialize because your game's {executableName}.exe seems to be invalid.\nThis may be a pirated version which modified the executable in an incompatible way; if so, you can try a different download or buy a legitimate version.\n\nTechnical details:\n{ex}"); + } catch (Exception ex) { Console.WriteLine($"SMAPI failed to initialize: {ex}"); @@ -77,8 +82,7 @@ namespace StardewModdingAPI /// This must be checked *before* any references to , and this method should not reference itself to avoid errors in Mono. private static void AssertGamePresent() { - Platform platform = EnvironmentUtility.DetectPlatform(); - string gameAssemblyName = platform == Platform.Windows ? "Stardew Valley" : "StardewValley"; + string gameAssemblyName = Program.GetExecutableAssemblyName(); if (Type.GetType($"StardewValley.Game1, {gameAssemblyName}", throwOnError: false) == null) Program.PrintErrorAndExit("Oops! SMAPI can't find the game. Make sure you're running StardewModdingAPI.exe in your game folder. See the readme.txt file for details."); } @@ -102,6 +106,13 @@ namespace StardewModdingAPI } + /// Get the game's executable assembly name. + private static string GetExecutableAssemblyName() + { + Platform platform = EnvironmentUtility.DetectPlatform(); + return platform == Platform.Windows ? "Stardew Valley" : "StardewValley"; + } + /// Initialize SMAPI and launch the game. /// The command-line arguments. /// This method is separate from because that can't contain any references to assemblies loaded by (e.g. via ), or Mono will incorrectly show an assembly resolution error before assembly resolution is set up. -- cgit From 88dce820d52f7e09ce5424e13b34d6c10d5868ed Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 4 Nov 2019 16:50:00 -0500 Subject: no longer omit zero patch numbers when formatting versions --- docs/release-notes.md | 1 + src/SMAPI.Tests/Utilities/SemanticVersionTests.cs | 12 ++++++------ src/SMAPI.Toolkit/SemanticVersion.cs | 14 ++++---------- src/SMAPI/Framework/GameVersion.cs | 3 +++ 4 files changed, 14 insertions(+), 16 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 7cd7b52b..1d933f96 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -107,6 +107,7 @@ For modders: * Trace logs for a broken mod now list all detected issues (instead of the first one). * Trace logs when loading mods are now more clear. * Clarified update-check errors for mods with multiple update keys. + * `SemanticVersion` no longer omits `.0` patch numbers when formatting versions, for better [semver](https://semver.org/) conformity (e.g. `3.0` is now formatted as `3.0.0`). * Updated dependencies (including Json.NET 11.0.2 → 12.0.2 and Mono.Cecil 0.10.1 → 0.11). * Fixes: * Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted. diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs index 8da64c27..c91ec27f 100644 --- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs +++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs @@ -18,10 +18,10 @@ namespace SMAPI.Tests.Utilities ** Constructor ****/ [Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from a string.")] - [TestCase("1.0", ExpectedResult = "1.0")] - [TestCase("1.0.0", ExpectedResult = "1.0")] + [TestCase("1.0", ExpectedResult = "1.0.0")] + [TestCase("1.0.0", ExpectedResult = "1.0.0")] [TestCase("3000.4000.5000", ExpectedResult = "3000.4000.5000")] - [TestCase("1.2-some-tag.4", ExpectedResult = "1.2-some-tag.4")] + [TestCase("1.2-some-tag.4", ExpectedResult = "1.2.0-some-tag.4")] [TestCase("1.2.3-some-tag.4", ExpectedResult = "1.2.3-some-tag.4")] [TestCase("1.2.3-SoME-tAg.4", ExpectedResult = "1.2.3-SoME-tAg.4")] [TestCase("1.2.3-some-tag.4 ", ExpectedResult = "1.2.3-some-tag.4")] @@ -31,7 +31,7 @@ namespace SMAPI.Tests.Utilities } [Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from the individual numbers.")] - [TestCase(1, 0, 0, null, ExpectedResult = "1.0")] + [TestCase(1, 0, 0, null, ExpectedResult = "1.0.0")] [TestCase(3000, 4000, 5000, null, ExpectedResult = "3000.4000.5000")] [TestCase(1, 2, 3, "", ExpectedResult = "1.2.3")] [TestCase(1, 2, 3, " ", ExpectedResult = "1.2.3")] @@ -66,7 +66,7 @@ namespace SMAPI.Tests.Utilities } [Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from an assembly version.")] - [TestCase(1, 0, 0, ExpectedResult = "1.0")] + [TestCase(1, 0, 0, ExpectedResult = "1.0.0")] [TestCase(1, 2, 3, ExpectedResult = "1.2.3")] [TestCase(3000, 4000, 5000, ExpectedResult = "3000.4000.5000")] public string Constructor_FromAssemblyVersion(int major, int minor, int patch) @@ -247,7 +247,7 @@ namespace SMAPI.Tests.Utilities ** Serializable ****/ [Test(Description = "Assert that SemanticVersion can be round-tripped through JSON with no special configuration.")] - [TestCase("1.0")] + [TestCase("1.0.0")] public void Serializable(string versionStr) { // act diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs index 6d5d65ac..2ce3578e 100644 --- a/src/SMAPI.Toolkit/SemanticVersion.cs +++ b/src/SMAPI.Toolkit/SemanticVersion.cs @@ -172,16 +172,10 @@ namespace StardewModdingAPI.Toolkit /// Get a string representation of the version. public override string ToString() { - // version - string result = this.PatchVersion != 0 - ? $"{this.MajorVersion}.{this.MinorVersion}.{this.PatchVersion}" - : $"{this.MajorVersion}.{this.MinorVersion}"; - - // tag - string tag = this.PrereleaseTag; - if (tag != null) - result += $"-{tag}"; - return result; + string version = $"{this.MajorVersion}.{this.MinorVersion}.{this.PatchVersion}"; + if (this.PrereleaseTag != null) + version += $"-{this.PrereleaseTag}"; + return version; } /// Parse a version string without throwing an exception if it fails. diff --git a/src/SMAPI/Framework/GameVersion.cs b/src/SMAPI/Framework/GameVersion.cs index b9ef12c8..cd88895c 100644 --- a/src/SMAPI/Framework/GameVersion.cs +++ b/src/SMAPI/Framework/GameVersion.cs @@ -12,6 +12,7 @@ namespace StardewModdingAPI.Framework /// A mapping of game to semantic versions. private static readonly IDictionary VersionMap = new Dictionary(StringComparer.InvariantCultureIgnoreCase) { + ["1.0"] = "1.0.0", ["1.01"] = "1.0.1", ["1.02"] = "1.0.2", ["1.03"] = "1.0.3", @@ -23,6 +24,8 @@ namespace StardewModdingAPI.Framework ["1.07"] = "1.0.7", ["1.07a"] = "1.0.8-prerelease1", ["1.08"] = "1.0.8", + ["1.1"] = "1.1.0", + ["1.2"] = "1.2.0", ["1.11"] = "1.1.1" }; -- cgit From 39214fd23f20b8c6d6f4e753e84b87f111ddf083 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 8 Nov 2019 22:48:49 -0500 Subject: update game log filters (#638) --- src/SMAPI/Framework/SCore.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index bfdf1c51..f7545bd2 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -86,15 +86,20 @@ namespace StardewModdingAPI.Framework /// Whether the program has been disposed. private bool IsDisposed; - /// Regex patterns which match console messages to suppress from the console and log. + /// Regex patterns which match console non-error messages to suppress from the console and log. private readonly Regex[] SuppressConsolePatterns = { new Regex(@"^TextBox\.Selected is now '(?:True|False)'\.$", RegexOptions.Compiled | RegexOptions.CultureInvariant), new Regex(@"^(?:FRUIT )?TREE: IsClient:(?:True|False) randomOutput: \d+$", RegexOptions.Compiled | RegexOptions.CultureInvariant), new Regex(@"^loadPreferences\(\); begin", RegexOptions.Compiled | RegexOptions.CultureInvariant), new Regex(@"^savePreferences\(\); async=", RegexOptions.Compiled | RegexOptions.CultureInvariant), - new Regex(@"^DebugOutput:\s+(?:added CLOUD|added cricket|dismount tile|Ping|playerPos)", RegexOptions.Compiled | RegexOptions.CultureInvariant), - new Regex(@"^static SerializableDictionary<.+>\(\) called\.$", RegexOptions.Compiled | RegexOptions.CultureInvariant), + new Regex(@"^DebugOutput:\s+(?:added CLOUD|added cricket|dismount tile|Ping|playerPos)", RegexOptions.Compiled | RegexOptions.CultureInvariant) + }; + + /// Regex patterns which match console error messages to suppress from the console and log. + private readonly Regex[] SuppressConsoleErrorPatterns = + { + new Regex(@"^Error loading schedule data for (?:Bouncer|Dwarf|Gunther|Krobus|Marlon|Mister Qi|Sandy|Wizard): .+ ---> System\.IO\.FileNotFoundException", RegexOptions.Compiled | RegexOptions.CultureInvariant) }; /// Regex patterns which match console messages to show a more friendly error for. @@ -1347,6 +1352,8 @@ namespace StardewModdingAPI.Framework // ignore suppressed message if (level != LogLevel.Error && this.SuppressConsolePatterns.Any(p => p.IsMatch(message))) return; + if (level == LogLevel.Error && this.SuppressConsoleErrorPatterns.Any(p => p.IsMatch(message))) + return; // show friendly error if applicable foreach (var entry in this.ReplaceConsolePatterns) -- cgit From 012ff7ec4335d48d7542ac9631b132fdbdc9f2d8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 8 Nov 2019 22:53:51 -0500 Subject: update for NPC schedule changes (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 14ce5aaa..a6bfab5c 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -777,6 +777,8 @@ namespace StardewModdingAPI.Metadata foreach (NPC villager in villagers) { // reload schedule + this.Reflection.GetField(villager, "_hasLoadedMasterScheduleData").SetValue(false); + this.Reflection.GetField>(villager, "_masterScheduleData").SetValue(null); villager.Schedule = villager.getSchedule(Game1.dayOfMonth); if (villager.Schedule == null) { -- cgit From 01db5e364d0db74f480dacd20877cc5d4728d60c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 9 Nov 2019 00:09:12 -0500 Subject: filter another new error (#638) --- 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 f7545bd2..50bd562a 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -99,7 +99,7 @@ namespace StardewModdingAPI.Framework /// Regex patterns which match console error messages to suppress from the console and log. private readonly Regex[] SuppressConsoleErrorPatterns = { - new Regex(@"^Error loading schedule data for (?:Bouncer|Dwarf|Gunther|Krobus|Marlon|Mister Qi|Sandy|Wizard): .+ ---> System\.IO\.FileNotFoundException", RegexOptions.Compiled | RegexOptions.CultureInvariant) + new Regex(@"^Error loading schedule data for (?:Bouncer|Dwarf|Gunther|Henchman|Krobus|Marlon|Mister Qi|Sandy|Wizard): .+ ---> System\.IO\.FileNotFoundException", RegexOptions.Compiled | RegexOptions.CultureInvariant) }; /// Regex patterns which match console messages to show a more friendly error for. -- cgit From fd6a719b02d1d45d27509f44f09eefe52124ee20 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 9 Nov 2019 21:18:06 -0500 Subject: overhaul update checks This commit moves the core update-check logic serverside, and adds support for community-defined version mappings. For example, that means false update alerts can now be solved by the community for all players. --- docs/release-notes.md | 4 + docs/technical/web.md | 209 ++++++++++++++++++--- .../Framework/Clients/WebApi/ModEntryModel.cs | 18 +- .../Clients/WebApi/ModExtendedMetadataModel.cs | 24 ++- .../Framework/Clients/WebApi/ModSeachModel.cs | 36 ---- .../Clients/WebApi/ModSearchEntryModel.cs | 11 +- .../Framework/Clients/WebApi/ModSearchModel.cs | 52 +++++ .../Framework/Clients/WebApi/WebApiClient.cs | 8 +- .../Framework/Clients/Wiki/WikiClient.cs | 26 +++ .../Framework/Clients/Wiki/WikiModEntry.cs | 7 + .../Framework/ModData/ModDataModel.cs | 6 - .../Framework/ModData/ModDataRecord.cs | 31 --- .../ModData/ModDataRecordVersionedFields.cs | 24 --- src/SMAPI.Web/Controllers/ModsApiController.cs | 162 +++++++++++++--- .../Framework/Caching/Wiki/CachedWikiMod.cs | 24 ++- src/SMAPI.Web/Views/Index/Privacy.cshtml | 2 +- src/SMAPI.Web/wwwroot/SMAPI.metadata.json | 97 ---------- src/SMAPI/Framework/SCore.cs | 57 ++---- 18 files changed, 493 insertions(+), 305 deletions(-) delete mode 100644 src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs create mode 100644 src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index eace8be5..5f643f07 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -18,6 +18,9 @@ For players: * **Improved mod scanning.** SMAPI now supports some non-standard mod structures automatically, improves compatibility with the Vortex mod manager, and improves various error/skip messages related to mod loading. +* **Overhauled update checks.** + SMAPI update checks are now handled entirely on the web server and support community-defined version mappings. For example, that means false update alerts can now be solved by the community for all players. + * **Fixed many bugs and edge cases.** For modders: @@ -50,6 +53,7 @@ For modders: * Added update checks for CurseForge mods. * Added support for configuring console colors via `smapi-internal/config.json` (intended for players with unusual consoles). * Added support for specifying SMAPI command-line arguments as environment variables for Linux/Mac compatibility. + * Overhauled update checks and added community-defined version mapping. * Improved launch script compatibility on Linux (thanks to kurumushi and toastal!). * Made error messages more user-friendly in some cases. * Save Backup now works in the background, to avoid affecting startup time for players with a large number of saves. diff --git a/docs/technical/web.md b/docs/technical/web.md index 719b9433..78d93625 100644 --- a/docs/technical/web.md +++ b/docs/technical/web.md @@ -116,54 +116,201 @@ SMAPI provides a web API at `api.smapi.io` for use by SMAPI and external tools. accessible but not officially released; it may change at any time. ### `/mods` endpoint -The API has one `/mods` endpoint. This provides mod info, including official versions and URLs -(from Chucklefish, GitHub, or Nexus), unofficial versions from the wiki, and optional mod metadata -from the wiki and SMAPI's internal data. This is used by SMAPI to perform update checks, and by -external tools to fetch mod data. +The API has one `/mods` endpoint. This crossreferences the mod against a variety of sources (e.g. +the wiki, Chucklefish, CurseForge, ModDrop, and Nexus) to provide metadata mainly intended for +update checks. -The API accepts a `POST` request with the mods to match, each of which **must** specify an ID and -may _optionally_ specify [update keys](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Manifest#Update_checks). -The API will automatically try to fetch known update keys from the wiki and internal data based on -the given ID. +The API accepts a `POST` request with these fields: -``` -POST https://api.smapi.io/v2.0/mods + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
fieldsummary
mods + +The mods for which to fetch metadata. Included fields: + + +field | summary +----- | ------- +`id` | The unique ID in the mod's `manifest.json`. This is used to crossreference with the wiki, and to index mods in the response. If it's unknown (e.g. you just have an update key), you can use a unique fake ID like `FAKE.Nexus.2400`. +`updateKeys` | _(optional)_ [Update keys](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Manifest#Update_checks) which specify the mod pages to check, in addition to any mod pages linked to the `ID`. +`installedVersion` | _(optional)_ The installed version of the mod. If not specified, the API won't recommend an update. +`isBroken` | _(optional)_ Whether SMAPI failed to load the installed version of the mod, e.g. due to incompatibility. If true, the web API will be more permissive when recommending updates (e.g. allowing a stable → prerelease update). + +
apiVersion + +_(optional)_ The installed version of SMAPI. If not specified, the API won't recommend an update. + +
gameVersion + +_(optional)_ The installed version of Stardew Valley. This may be used to select updates. + +
platform + +_(optional)_ The player's OS (`Android`, `Linux`, `Mac`, or `Windows`). This may be used to select updates. + +
includeExtendedMetadata + +_(optional)_ Whether to include extra metadata that's not needed for SMAPI update checks, but which +may be useful to external tools. + +
+ +Example request: +```js +POST https://api.smapi.io/v3.0/mods { "mods": [ { - "id": "Pathoschild.LookupAnything", - "updateKeys": [ "nexus:541", "chucklefish:4250" ] + "id": "Pathoschild.ContentPatcher", + "updateKeys": [ "nexus:1915" ], + "installedVersion": "1.9.2", + "isBroken": false } ], + "apiVersion": "3.0.0", + "gameVersion": "1.4.0", + "platform": "Windows", "includeExtendedMetadata": true } ``` -The API will automatically aggregate versions and errors. Each mod will include... -* an `id` (matching what you passed in); -* up to three versions: `main` (e.g. 'latest version' field on Nexus), `optional` if newer (e.g. - optional files on Nexus), and `unofficial` if newer (from the wiki); -* `metadata` with mod info crossreferenced from the wiki and internal data (only if you specified - `includeExtendedMetadata: true`); -* and `errors` containing any error messages that occurred while fetching data. - -For example: +Response fields: + + + + + + + + + + + + + + + + + + + + + + + + + + +
fieldsummary
id + +The mod ID you specified in the request. + +
suggestedUpdate + +The update version recommended by the web API, if any. This is based on some internal rules (e.g. +it won't recommend a prerelease update if the player has a working stable version) and context +(e.g. whether the player is in the game beta channel). Choosing an update version yourself isn't +recommended, but you can set `includeExtendedMetadata: true` and check the `metadata` field if you +really want to do that. + +
errors + +Human-readable errors that occurred fetching the version info (e.g. if a mod page has an invalid +version). + +
metadata + +Extra metadata that's not needed for SMAPI update checks but which may be useful to external tools, +if you set `includeExtendedMetadata: true` in the request. Included fields: + +field | summary +----- | ------- +`id` | The known `manifest.json` unique IDs for this mod defined on the wiki, if any. That includes historical versions of the mod. +`name` | The normalised name for this mod based on the crossreferenced sites. +`nexusID` | The mod ID on [Nexus Mods](https://www.nexusmods.com/stardewvalley/), if any. +`chucklefishID` | The mod ID in the [Chucklefish mod repo](https://community.playstarbound.com/resources/categories/stardew-valley.22/), if any. +`curseForgeID` | The mod project ID on [CurseForge](https://www.curseforge.com/stardewvalley), if any. +`curseForgeKey` | The mod key on [CurseForge](https://www.curseforge.com/stardewvalley), if any. This is used in the mod page URL. +`modDropID` | The mod ID on [ModDrop](https://www.moddrop.com/stardew-valley), if any. +`gitHubRepo` | The GitHub repository containing the mod code, if any. Specified in the `Owner/Repo` form. +`customSourceUrl` | The custom URL to the mod code, if any. This is used for mods which aren't stored in a GitHub repo. +`customUrl` | The custom URL to the mod page, if any. This is used for mods which aren't stored on one of the standard mod sites covered by the ID fields. +`main` | The primary mod version, if any. This depends on the mod site, but it's typically either the version of the mod itself or of its latest non-optional download. +`optional` | The latest optional download version, if any. +`unofficial` | The version of the unofficial update defined on the wiki for this mod, if any. +`unofficialForBeta` | Equivalent to `unofficial`, but for beta versions of SMAPI or Stardew Valley. +`hasBetaInfo` | Whether there's an ongoing Stardew Valley or SMAPI beta which may affect update checks. +`compatibilityStatus` | The compatibility status for the mod for the stable version of the game, as defined on the wiki, if any. See [possible values](https://github.com/Pathoschild/SMAPI/blob/develop/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiCompatibilityStatus.cs). +`compatibilitySummary` | The human-readable summary of the mod's compatibility in HTML format, if any. +`brokeIn` | The SMAPI or Stardew Valley version that broke this mod, if any. +`betaCompatibilityStatus`
`betaCompatibilitySummary`
`betaBrokeIn` | Equivalent to the preceding fields, but for beta versions of SMAPI or Stardew Valley. + + +
+ +Example response with `includeExtendedMetadata: false`: +```js +[ + { + "id": "Pathoschild.ContentPatcher", + "suggestedUpdate": { + "version": "1.10.0", + "url": "https://www.nexusmods.com/stardewvalley/mods/1915" + }, + "errors": [] + } +] ``` + +Example response with `includeExtendedMetadata: true`: +```js [ { - "id": "Pathoschild.LookupAnything", - "main": { - "version": "1.19", - "url": "https://www.nexusmods.com/stardewvalley/mods/541" + "id": "Pathoschild.ContentPatcher", + "suggestedUpdate": { + "version": "1.10.0", + "url": "https://www.nexusmods.com/stardewvalley/mods/1915" }, "metadata": { - "id": [ - "Pathoschild.LookupAnything", - "LookupAnything" - ], - "name": "Lookup Anything", - "nexusID": 541, + "id": [ "Pathoschild.ContentPatcher" ], + "name": "Content Patcher", + "nexusID": 1915, + "curseForgeID": 309243, + "curseForgeKey": "content-patcher", + "modDropID": 470174, "gitHubRepo": "Pathoschild/StardewMods", + "main": { + "version": "1.10", + "url": "https://www.nexusmods.com/stardewvalley/mods/1915" + }, + "hasBetaInfo": true, "compatibilityStatus": "Ok", "compatibilitySummary": "✓ use latest version." }, diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs index 8a9c0a25..f1bcfccc 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModEntryModel.cs @@ -1,3 +1,5 @@ +using System; + namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi { /// Metadata about a mod. @@ -9,23 +11,31 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The mod's unique ID (if known). public string ID { get; set; } + /// The update version recommended by the web API based on its version update and mapping rules. + public ModEntryVersionModel SuggestedUpdate { get; set; } + + /// Optional extended data which isn't needed for update checks. + public ModExtendedMetadataModel Metadata { get; set; } + /// The main version. + [Obsolete] public ModEntryVersionModel Main { get; set; } /// The latest optional version, if newer than . + [Obsolete] public ModEntryVersionModel Optional { get; set; } /// The latest unofficial version, if newer than and . + [Obsolete] public ModEntryVersionModel Unofficial { get; set; } /// The latest unofficial version for the current Stardew Valley or SMAPI beta, if any (see ). + [Obsolete] public ModEntryVersionModel UnofficialForBeta { get; set; } - /// Optional extended data which isn't needed for update checks. - public ModExtendedMetadataModel Metadata { get; set; } - /// Whether a Stardew Valley or SMAPI beta which affects mod compatibility is in progress. If this is true, should be used for beta versions of SMAPI instead of . - public bool HasBetaInfo { get; set; } + [Obsolete] + public bool? HasBetaInfo { get; set; } /// The errors that occurred while fetching update data. public string[] Errors { get; set; } = new string[0]; diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs index 8074210c..4a697585 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs @@ -46,6 +46,17 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The custom mod page URL (if applicable). public string CustomUrl { get; set; } + /// The main version. + public ModEntryVersionModel Main { get; set; } + + /// The latest optional version, if newer than . + public ModEntryVersionModel Optional { get; set; } + + /// The latest unofficial version, if newer than and . + public ModEntryVersionModel Unofficial { get; set; } + + /// The latest unofficial version for the current Stardew Valley or SMAPI beta, if any (see ). + public ModEntryVersionModel UnofficialForBeta { get; set; } /**** ** Stable compatibility @@ -60,7 +71,6 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The game or SMAPI version which broke this mod, if applicable. public string BrokeIn { get; set; } - /**** ** Beta compatibility ****/ @@ -84,8 +94,18 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Construct an instance. /// The mod metadata from the wiki (if available). /// The mod metadata from SMAPI's internal DB (if available). - public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db) + /// The main version. + /// The latest optional version, if newer than . + /// The latest unofficial version, if newer than and . + /// The latest unofficial version for the current Stardew Valley or SMAPI beta, if any. + public ModExtendedMetadataModel(WikiModEntry wiki, ModDataRecord db, ModEntryVersionModel main, ModEntryVersionModel optional, ModEntryVersionModel unofficial, ModEntryVersionModel unofficialForBeta) { + // versions + this.Main = main; + this.Optional = optional; + this.Unofficial = unofficial; + this.UnofficialForBeta = unofficialForBeta; + // wiki data if (wiki != null) { diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs deleted file mode 100644 index a2eaad16..00000000 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSeachModel.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Linq; - -namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi -{ - /// Specifies mods whose update-check info to fetch. - public class ModSearchModel - { - /********* - ** Accessors - *********/ - /// The mods for which to find data. - public ModSearchEntryModel[] Mods { get; set; } - - /// Whether to include extended metadata for each mod. - public bool IncludeExtendedMetadata { get; set; } - - - /********* - ** Public methods - *********/ - /// Construct an empty instance. - public ModSearchModel() - { - // needed for JSON deserializing - } - - /// Construct an instance. - /// The mods to search. - /// Whether to include extended metadata for each mod. - public ModSearchModel(ModSearchEntryModel[] mods, bool includeExtendedMetadata) - { - this.Mods = mods.ToArray(); - this.IncludeExtendedMetadata = includeExtendedMetadata; - } - } -} diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs index 886cd5a1..bf81e102 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchEntryModel.cs @@ -12,6 +12,12 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The namespaced mod update keys (if available). public string[] UpdateKeys { get; set; } + /// The mod version installed by the local player. This is used for version mapping in some cases. + public ISemanticVersion InstalledVersion { get; set; } + + /// Whether the installed version is broken or could not be loaded. + public bool IsBroken { get; set; } + /********* ** Public methods @@ -24,10 +30,13 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Construct an instance. /// The unique mod ID. + /// The version installed by the local player. This is used for version mapping in some cases. /// The namespaced mod update keys (if available). - public ModSearchEntryModel(string id, string[] updateKeys) + /// Whether the installed version is broken or could not be loaded. + public ModSearchEntryModel(string id, ISemanticVersion installedVersion, string[] updateKeys, bool isBroken = false) { this.ID = id; + this.InstalledVersion = installedVersion; this.UpdateKeys = updateKeys ?? new string[0]; } } diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs new file mode 100644 index 00000000..73698173 --- /dev/null +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/ModSearchModel.cs @@ -0,0 +1,52 @@ +using System.Linq; +using StardewModdingAPI.Toolkit.Utilities; + +namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi +{ + /// Specifies mods whose update-check info to fetch. + public class ModSearchModel + { + /********* + ** Accessors + *********/ + /// The mods for which to find data. + public ModSearchEntryModel[] Mods { get; set; } + + /// Whether to include extended metadata for each mod. + public bool IncludeExtendedMetadata { get; set; } + + /// The SMAPI version installed by the player. This is used for version mapping in some cases. + public ISemanticVersion ApiVersion { get; set; } + + /// The Stardew Valley version installed by the player. + public ISemanticVersion GameVersion { get; set; } + + /// The OS on which the player plays. + public Platform? Platform { get; set; } + + + /********* + ** Public methods + *********/ + /// Construct an empty instance. + public ModSearchModel() + { + // needed for JSON deserializing + } + + /// Construct an instance. + /// The mods to search. + /// The SMAPI version installed by the player. If this is null, the API won't provide a recommended update. + /// The Stardew Valley version installed by the player. + /// The OS on which the player plays. + /// Whether to include extended metadata for each mod. + public ModSearchModel(ModSearchEntryModel[] mods, ISemanticVersion apiVersion, ISemanticVersion gameVersion, Platform platform, bool includeExtendedMetadata) + { + this.Mods = mods.ToArray(); + this.ApiVersion = apiVersion; + this.GameVersion = gameVersion; + this.Platform = platform; + this.IncludeExtendedMetadata = includeExtendedMetadata; + } + } +} diff --git a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs index 80c8f62b..f0a7c82a 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/WebApi/WebApiClient.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net; using Newtonsoft.Json; using StardewModdingAPI.Toolkit.Serialization; +using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi { @@ -37,12 +38,15 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// Get metadata about a set of mods from the web API. /// The mod keys for which to fetch the latest version. + /// The SMAPI version installed by the player. If this is null, the API won't provide a recommended update. + /// The Stardew Valley version installed by the player. + /// The OS on which the player plays. /// Whether to include extended metadata for each mod. - public IDictionary GetModInfo(ModSearchEntryModel[] mods, bool includeExtendedMetadata = false) + public IDictionary GetModInfo(ModSearchEntryModel[] mods, ISemanticVersion apiVersion, ISemanticVersion gameVersion, Platform platform, bool includeExtendedMetadata = false) { return this.Post( $"v{this.Version}/mods", - new ModSearchModel(mods, includeExtendedMetadata) + new ModSearchModel(mods, apiVersion, gameVersion, platform, includeExtendedMetadata) ).ToDictionary(p => p.ID); } diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs index 610e14f1..384f23fc 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs @@ -102,6 +102,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki string anchor = this.GetAttribute(node, "id"); string contentPackFor = this.GetAttribute(node, "data-content-pack-for"); string devNote = this.GetAttribute(node, "data-dev-note"); + IDictionary mapLocalVersions = this.GetAttributeAsVersionMapping(node, "data-map-local-versions"); + IDictionary mapRemoteVersions = this.GetAttributeAsVersionMapping(node, "data-map-remote-versions"); // parse stable compatibility WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo @@ -159,6 +161,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki Warnings = warnings, MetadataLinks = metadataLinks.ToArray(), DevNote = devNote, + MapLocalVersions = mapLocalVersions, + MapRemoteVersions = mapRemoteVersions, Anchor = anchor }; } @@ -223,6 +227,28 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki return null; } + /// Get an attribute value and parse it as a version mapping. + /// The element whose attributes to read. + /// The attribute name. + private IDictionary GetAttributeAsVersionMapping(HtmlNode element, string name) + { + // get raw value + string raw = this.GetAttribute(element, name); + if (raw?.Contains("→") != true) + return null; + + // parse + // Specified on the wiki in the form "remote version → mapped version; another remote version → mapped version" + IDictionary map = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + foreach (string pair in raw.Split(';')) + { + string[] versions = pair.Split('→'); + if (versions.Length == 2 && !string.IsNullOrWhiteSpace(versions[0]) && !string.IsNullOrWhiteSpace(versions[1])) + map[versions[0].Trim()] = versions[1].Trim(); + } + return map; + } + /// Get the text of an element with the given class name. /// The metadata container. /// The field name. diff --git a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs index 51bb2336..931dcd43 100644 --- a/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ b/src/SMAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki { @@ -62,6 +63,12 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki /// Special notes intended for developers who maintain unofficial updates or submit pull requests. public string DevNote { get; set; } + /// Maps local versions to a semantic version for update checks. + public IDictionary MapLocalVersions { get; set; } + + /// Maps remote versions to a semantic version for update checks. + public IDictionary MapRemoteVersions { get; set; } + /// The link anchor for the mod entry in the wiki compatibility list. public string Anchor { get; set; } } diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs index dd0bd07b..8b40c301 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataModel.cs @@ -25,12 +25,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// public string FormerIDs { get; set; } - /// Maps local versions to a semantic version for update checks. - public IDictionary MapLocalVersions { get; set; } = new Dictionary(); - - /// Maps remote versions to a semantic version for update checks. - public IDictionary MapRemoteVersions { get; set; } = new Dictionary(); - /// The mod warnings to suppress, even if they'd normally be shown. public ModWarning SuppressWarnings { get; set; } diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs index f01ada7c..c892d820 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecord.cs @@ -22,12 +22,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// The mod warnings to suppress, even if they'd normally be shown. public ModWarning SuppressWarnings { get; set; } - /// Maps local versions to a semantic version for update checks. - public IDictionary MapLocalVersions { get; } - - /// Maps remote versions to a semantic version for update checks. - public IDictionary MapRemoteVersions { get; } - /// The versioned field data. public ModDataField[] Fields { get; } @@ -44,8 +38,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData this.ID = model.ID; this.FormerIDs = model.GetFormerIDs().ToArray(); this.SuppressWarnings = model.SuppressWarnings; - this.MapLocalVersions = new Dictionary(model.MapLocalVersions, StringComparer.InvariantCultureIgnoreCase); - this.MapRemoteVersions = new Dictionary(model.MapRemoteVersions, StringComparer.InvariantCultureIgnoreCase); this.Fields = model.GetFields().ToArray(); } @@ -67,29 +59,6 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData return false; } - /// Get a semantic local version for update checks. - /// The remote version to normalize. - public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) - { - return this.MapLocalVersions != null && this.MapLocalVersions.TryGetValue(version.ToString(), out string newVersion) - ? new SemanticVersion(newVersion) - : version; - } - - /// Get a semantic remote version for update checks. - /// The remote version to normalize. - public string GetRemoteVersionForUpdateChecks(string version) - { - // normalize version if possible - if (SemanticVersion.TryParse(version, out ISemanticVersion parsed)) - version = parsed.ToString(); - - // fetch remote version - return this.MapRemoteVersions != null && this.MapRemoteVersions.TryGetValue(version, out string newVersion) - ? newVersion - : version; - } - /// Get the possible mod IDs. public IEnumerable GetIDs() { diff --git a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs index 9e22990d..598da66a 100644 --- a/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs +++ b/src/SMAPI.Toolkit/Framework/ModData/ModDataRecordVersionedFields.cs @@ -26,29 +26,5 @@ namespace StardewModdingAPI.Toolkit.Framework.ModData /// The upper version for which the applies (if any). public ISemanticVersion StatusUpperVersion { get; set; } - - - /********* - ** Public methods - *********/ - /// Get a semantic local version for update checks. - /// The remote version to normalize. - public ISemanticVersion GetLocalVersionForUpdateChecks(ISemanticVersion version) - { - return this.DataRecord.GetLocalVersionForUpdateChecks(version); - } - - /// Get a semantic remote version for update checks. - /// The remote version to normalize. - public ISemanticVersion GetRemoteVersionForUpdateChecks(ISemanticVersion version) - { - if (version == null) - return null; - - string rawVersion = this.DataRecord.GetRemoteVersionForUpdateChecks(version.ToString()); - return rawVersion != null - ? new SemanticVersion(rawVersion) - : version; - } } } diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index f65b164f..fe220eb5 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -80,7 +80,7 @@ namespace StardewModdingAPI.Web.Controllers new IModRepository[] { new ChucklefishRepository(chucklefish), - new CurseForgeRepository(curseForge), + new CurseForgeRepository(curseForge), new GitHubRepository(github), new ModDropRepository(modDrop), new NexusRepository(nexus) @@ -90,12 +90,15 @@ namespace StardewModdingAPI.Web.Controllers /// Fetch version metadata for the given mods. /// The mod search criteria. + /// The requested API version. [HttpPost] - public async Task> PostAsync([FromBody] ModSearchModel model) + public async Task> PostAsync([FromBody] ModSearchModel model, [FromRoute] string version) { if (model?.Mods == null) return new ModEntryModel[0]; + bool legacyMode = SemanticVersion.TryParse(version, out ISemanticVersion parsedVersion) && parsedVersion.IsOlderThan("3.0.0-beta.20191109"); + // fetch wiki data WikiModEntry[] wikiData = this.WikiCache.GetWikiMods().Select(p => p.GetModel()).ToArray(); IDictionary mods = new Dictionary(StringComparer.CurrentCultureIgnoreCase); @@ -104,7 +107,25 @@ namespace StardewModdingAPI.Web.Controllers if (string.IsNullOrWhiteSpace(mod.ID)) continue; - ModEntryModel result = await this.GetModData(mod, wikiData, model.IncludeExtendedMetadata); + ModEntryModel result = await this.GetModData(mod, wikiData, model.IncludeExtendedMetadata || legacyMode, model.ApiVersion); + if (legacyMode) + { + result.Main = result.Metadata.Main; + result.Optional = result.Metadata.Optional; + result.Unofficial = result.Metadata.Unofficial; + result.UnofficialForBeta = result.Metadata.UnofficialForBeta; + result.HasBetaInfo = result.Metadata.BetaCompatibilityStatus != null; + result.SuggestedUpdate = null; + if (!model.IncludeExtendedMetadata) + result.Metadata = null; + } + else if (!model.IncludeExtendedMetadata && (model.ApiVersion == null || mod.InstalledVersion == null)) + { + var errors = new List(result.Errors); + errors.Add($"This API can't suggest an update because {nameof(model.ApiVersion)} or {nameof(mod.InstalledVersion)} are null, and you didn't specify {nameof(model.IncludeExtendedMetadata)} to get other info. See the SMAPI technical docs for usage."); + result.Errors = errors.ToArray(); + } + mods[mod.ID] = result; } @@ -120,8 +141,9 @@ namespace StardewModdingAPI.Web.Controllers /// The mod data to match. /// The wiki data. /// Whether to include extended metadata for each mod. + /// The SMAPI version installed by the player. /// Returns the mod data if found, else null. - private async Task GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata) + private async Task GetModData(ModSearchEntryModel search, WikiModEntry[] wikiData, bool includeExtendedMetadata, ISemanticVersion apiVersion) { // cross-reference data ModDataRecord record = this.ModDatabase.Get(search.ID); @@ -131,6 +153,10 @@ namespace StardewModdingAPI.Web.Controllers // get latest versions ModEntryModel result = new ModEntryModel { ID = search.ID }; IList errors = new List(); + ModEntryVersionModel main = null; + ModEntryVersionModel optional = null; + ModEntryVersionModel unofficial = null; + ModEntryVersionModel unofficialForBeta = null; foreach (UpdateKey updateKey in updateKeys) { // validate update key @@ -151,76 +177,118 @@ namespace StardewModdingAPI.Web.Controllers // handle main version if (data.Version != null) { - if (!SemanticVersion.TryParse(data.Version, out ISemanticVersion version)) + ISemanticVersion version = this.GetMappedVersion(data.Version, wikiEntry?.MapRemoteVersions); + if (version == null) { errors.Add($"The update key '{updateKey}' matches a mod with invalid semantic version '{data.Version}'."); continue; } - if (this.IsNewer(version, result.Main?.Version)) - result.Main = new ModEntryVersionModel(version, data.Url); + if (this.IsNewer(version, main?.Version)) + main = new ModEntryVersionModel(version, data.Url); } // handle optional version if (data.PreviewVersion != null) { - if (!SemanticVersion.TryParse(data.PreviewVersion, out ISemanticVersion version)) + ISemanticVersion version = this.GetMappedVersion(data.PreviewVersion, wikiEntry?.MapRemoteVersions); + if (version == null) { errors.Add($"The update key '{updateKey}' matches a mod with invalid optional semantic version '{data.PreviewVersion}'."); continue; } - if (this.IsNewer(version, result.Optional?.Version)) - result.Optional = new ModEntryVersionModel(version, data.Url); + if (this.IsNewer(version, optional?.Version)) + optional = new ModEntryVersionModel(version, data.Url); } } // get unofficial version - if (wikiEntry?.Compatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, result.Optional?.Version)) - result.Unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}"); + if (wikiEntry?.Compatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, optional?.Version)) + unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}"); // get unofficial version for beta if (wikiEntry?.HasBetaInfo == true) { - result.HasBetaInfo = true; if (wikiEntry.BetaCompatibility.Status == WikiCompatibilityStatus.Unofficial) { if (wikiEntry.BetaCompatibility.UnofficialVersion != null) { - result.UnofficialForBeta = (wikiEntry.BetaCompatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, result.Main?.Version) && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, result.Optional?.Version)) + unofficialForBeta = (wikiEntry.BetaCompatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, optional?.Version)) ? new ModEntryVersionModel(wikiEntry.BetaCompatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}") : null; } else - result.UnofficialForBeta = result.Unofficial; + unofficialForBeta = unofficial; } } // fallback to preview if latest is invalid - if (result.Main == null && result.Optional != null) + if (main == null && optional != null) { - result.Main = result.Optional; - result.Optional = null; + main = optional; + optional = null; } // special cases if (result.ID == "Pathoschild.SMAPI") { - if (result.Main != null) - result.Main.Url = "https://smapi.io/"; - if (result.Optional != null) - result.Optional.Url = "https://smapi.io/"; + if (main != null) + main.Url = "https://smapi.io/"; + if (optional != null) + optional.Url = "https://smapi.io/"; + } + + // get recommended update (if any) + ISemanticVersion installedVersion = this.GetMappedVersion(search.InstalledVersion?.ToString(), wikiEntry?.MapLocalVersions); + if (apiVersion != null && installedVersion != null) + { + // get newer versions + List updates = new List(); + if (this.IsRecommendedUpdate(installedVersion, main?.Version, useBetaChannel: true)) + updates.Add(main); + if (this.IsRecommendedUpdate(installedVersion, optional?.Version, useBetaChannel: installedVersion.IsPrerelease())) + updates.Add(optional); + if (this.IsRecommendedUpdate(installedVersion, unofficial?.Version, useBetaChannel: search.IsBroken)) + updates.Add(unofficial); + if (this.IsRecommendedUpdate(installedVersion, unofficialForBeta?.Version, useBetaChannel: apiVersion.IsPrerelease())) + updates.Add(unofficialForBeta); + + // get newest version + ModEntryVersionModel newest = null; + foreach (ModEntryVersionModel update in updates) + { + if (newest == null || update.Version.IsNewerThan(newest.Version)) + newest = update; + } + + // set field + result.SuggestedUpdate = newest != null + ? new ModEntryVersionModel(newest.Version, newest.Url) + : null; } // add extended metadata - if (includeExtendedMetadata && (wikiEntry != null || record != null)) - result.Metadata = new ModExtendedMetadataModel(wikiEntry, record); + if (includeExtendedMetadata) + result.Metadata = new ModExtendedMetadataModel(wikiEntry, record, main: main, optional: optional, unofficial: unofficial, unofficialForBeta: unofficialForBeta); // add result result.Errors = errors.ToArray(); return result; } + /// Get whether a given version should be offered to the user as an update. + /// The current semantic version. + /// The target semantic version. + /// Whether the user enabled the beta channel and should be offered prerelease updates. + private bool IsRecommendedUpdate(ISemanticVersion currentVersion, ISemanticVersion newVersion, bool useBetaChannel) + { + return + newVersion != null + && newVersion.IsNewerThan(currentVersion) + && (useBetaChannel || !newVersion.IsPrerelease()); + } + /// Get whether a version is newer than an version. /// The current version. /// The other version. @@ -260,7 +328,7 @@ namespace StardewModdingAPI.Web.Controllers /// The specified update keys. /// The mod's entry in SMAPI's internal database. /// The mod's entry in the wiki list. - public IEnumerable GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry) + private IEnumerable GetUpdateKeys(string[] specifiedKeys, ModDataRecord record, WikiModEntry entry) { IEnumerable GetRaw() { @@ -301,5 +369,49 @@ namespace StardewModdingAPI.Web.Controllers yield return key; } } + + /// Get a semantic local version for update checks. + /// The version to parse. + /// A map of version replacements. + private ISemanticVersion GetMappedVersion(string version, IDictionary map) + { + // try mapped version + string rawNewVersion = this.GetRawMappedVersion(version, map); + if (SemanticVersion.TryParse(rawNewVersion, out ISemanticVersion parsedNew)) + return parsedNew; + + // return original version + return SemanticVersion.TryParse(version, out ISemanticVersion parsedOld) + ? parsedOld + : null; + } + + /// Get a semantic local version for update checks. + /// The version to map. + /// A map of version replacements. + private string GetRawMappedVersion(string version, IDictionary map) + { + if (version == null || map == null || !map.Any()) + return version; + + // match exact raw version + if (map.ContainsKey(version)) + return map[version]; + + // match parsed version + if (SemanticVersion.TryParse(version, out ISemanticVersion parsed)) + { + if (map.ContainsKey(parsed.ToString())) + return map[parsed.ToString()]; + + foreach (var pair in map) + { + if (SemanticVersion.TryParse(pair.Key, out ISemanticVersion target) && parsed.Equals(target) && SemanticVersion.TryParse(pair.Value, out ISemanticVersion newVersion)) + return newVersion.ToString(); + } + } + + return version; + } } } diff --git a/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs b/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs index fddf99ee..8569984a 100644 --- a/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs +++ b/src/SMAPI.Web/Framework/Caching/Wiki/CachedWikiMod.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.Clients.Wiki; @@ -109,6 +112,17 @@ namespace StardewModdingAPI.Web.Framework.Caching.Wiki /// The URL to the latest unofficial update, if applicable. public string BetaUnofficialUrl { get; set; } + /**** + ** Version maps + ****/ + /// Maps local versions to a semantic version for update checks. + [BsonDictionaryOptions(Representation = DictionaryRepresentation.ArrayOfArrays)] + public IDictionary MapLocalVersions { get; set; } + + /// Maps remote versions to a semantic version for update checks. + [BsonDictionaryOptions(Representation = DictionaryRepresentation.ArrayOfArrays)] + public IDictionary MapRemoteVersions { get; set; } + /********* ** Accessors @@ -154,6 +168,10 @@ namespace StardewModdingAPI.Web.Framework.Caching.Wiki this.BetaBrokeIn = mod.BetaCompatibility?.BrokeIn; this.BetaUnofficialVersion = mod.BetaCompatibility?.UnofficialVersion?.ToString(); this.BetaUnofficialUrl = mod.BetaCompatibility?.UnofficialUrl; + + // version maps + this.MapLocalVersions = mod.MapLocalVersions; + this.MapRemoteVersions = mod.MapRemoteVersions; } /// Reconstruct the original model. @@ -186,7 +204,11 @@ namespace StardewModdingAPI.Web.Framework.Caching.Wiki BrokeIn = this.MainBrokeIn, UnofficialVersion = this.MainUnofficialVersion != null ? new SemanticVersion(this.MainUnofficialVersion) : null, UnofficialUrl = this.MainUnofficialUrl - } + }, + + // version maps + MapLocalVersions = this.MapLocalVersions, + MapRemoteVersions = this.MapRemoteVersions }; // beta compatibility diff --git a/src/SMAPI.Web/Views/Index/Privacy.cshtml b/src/SMAPI.Web/Views/Index/Privacy.cshtml index 356580b4..914384a8 100644 --- a/src/SMAPI.Web/Views/Index/Privacy.cshtml +++ b/src/SMAPI.Web/Views/Index/Privacy.cshtml @@ -24,7 +24,7 @@

This website and SMAPI's web API are hosted by Amazon Web Services. Their servers may automatically collect diagnostics like your IP address, but this information is not visible to SMAPI's web application or developers. For more information, see the Amazon Privacy Notice.

Update checks

-

SMAPI notifies you when there's a new version of SMAPI or your mods available. To do so, it sends your SMAPI and mod versions to its web API. No personal information is stored by the web application, but see web logging.

+

SMAPI notifies you when there's a new version of SMAPI or your mods available. To do so, it sends your game/SMAPI/mod versions and platform type to its web API. No personal information is stored by the web application, but see web logging.

You can disable update checks, and no information will be transmitted to the web API. To do so:

    diff --git a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json index e4c0a6f6..553b6934 100644 --- a/src/SMAPI.Web/wwwroot/SMAPI.metadata.json +++ b/src/SMAPI.Web/wwwroot/SMAPI.metadata.json @@ -14,11 +14,6 @@ * other fields if no ID was specified. This doesn't include the latest ID, if any. Multiple * variants can be separated with '|'. * - * - MapLocalVersions and MapRemoteVersions correct local manifest versions and remote versions - * during update checks. For example, if the API returns version '1.1-1078' where '1078' is - * intended to be a build number, MapRemoteVersions can map it to '1.1' when comparing to the - * mod's current version. This is only meant to support legacy mods with injected update keys. - * * Versioned metadata * ================== * Each record can also specify extra metadata using the field keys below. @@ -122,91 +117,6 @@ "Default | UpdateKey": "Nexus:1820" }, - - /********* - ** Map versions - *********/ - "Adjust Artisan Prices": { - "ID": "ThatNorthernMonkey.AdjustArtisanPrices", - "FormerIDs": "1e36d4ca-c7ef-4dfb-9927-d27a6c3c8bdc", // changed in 0.0.2-pathoschild-update - "MapRemoteVersions": { "0.01": "0.0.1" } - }, - - "Almighty Farming Tool": { - "ID": "439", - "MapRemoteVersions": { - "1.21": "1.2.1", - "1.22-unofficial.3.mizzion": "1.2.2-unofficial.3.mizzion" - } - }, - - "Basic Sprinkler Improved": { - "ID": "lrsk_sdvm_bsi.0117171308", - "MapRemoteVersions": { "1.0.2": "1.0.1-release" } // manifest not updated - }, - - "Better Shipping Box": { - "ID": "Kithio:BetterShippingBox", - "MapLocalVersions": { "1.0.1": "1.0.2" } - }, - - "Chefs Closet": { - "ID": "Duder.ChefsCloset", - "MapLocalVersions": { "1.3-1": "1.3" } - }, - - "Configurable Machines": { - "ID": "21da6619-dc03-4660-9794-8e5b498f5b97", - "MapLocalVersions": { "1.2-beta": "1.2" } - }, - - "Crafting Counter": { - "ID": "lolpcgaming.CraftingCounter", - "MapRemoteVersions": { "1.1": "1.0" } // not updated in manifest - }, - - "Custom Linens": { - "ID": "Mevima.CustomLinens", - "MapRemoteVersions": { "1.1": "1.0" } // manifest not updated - }, - - "Dynamic Horses": { - "ID": "Bpendragon-DynamicHorses", - "MapRemoteVersions": { "1.2": "1.1-release" } // manifest not updated - }, - - "Dynamic Machines": { - "ID": "DynamicMachines", - "MapLocalVersions": { "1.1": "1.1.1" } - }, - - "Multiple Sprites and Portraits On Rotation (File Loading)": { - "ID": "FileLoading", - "MapLocalVersions": { "1.1": "1.12" } - }, - - "Relationship Status": { - "ID": "relationshipstatus", - "MapRemoteVersions": { "1.0.5": "1.0.4" } // not updated in manifest - }, - - "ReRegeneration": { - "ID": "lrsk_sdvm_rerg.0925160827", - "MapLocalVersions": { "1.1.2-release": "1.1.2" } - }, - - "Showcase Mod": { - "ID": "Igorious.Showcase", - "MapLocalVersions": { "0.9-500": "0.9" } - }, - - "Siv's Marriage Mod": { - "ID": "6266959802", // official version - "FormerIDs": "Siv.MarriageMod | medoli900.Siv's Marriage Mod", // 1.2.3-unofficial versions - "MapLocalVersions": { "0.0": "1.4" } - }, - - /********* ** Obsolete *********/ @@ -477,12 +387,6 @@ "~1.0.0 | Status": "AssumeBroken" // broke in Stardew Valley 1.3.29 (runtime errors) }, - "Skill Prestige: Cooking Adapter": { - "ID": "Alphablackwolf.CookingSkillPrestigeAdapter", - "FormerIDs": "20d6b8a3-b6e7-460b-a6e4-07c2b0cb6c63", // changed circa 1.1 - "MapRemoteVersions": { "1.2.3": "1.1" } // manifest not updated - }, - "Skull Cave Saver": { "ID": "cantorsdust.SkullCaveSaver", "FormerIDs": "8ac06349-26f7-4394-806c-95d48fd35774 | community.SkullCaveSaver", // changed in 1.1 and 1.2.2 @@ -501,7 +405,6 @@ "Stephan's Lots of Crops": { "ID": "stephansstardewcrops", - "MapRemoteVersions": { "1.41": "1.1" }, // manifest not updated "~1.1 | Status": "AssumeBroken" // broke in SDV 1.3 (overwrites vanilla items) }, diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 50bd562a..77b17c8a 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -593,27 +593,19 @@ namespace StardewModdingAPI.Framework ISemanticVersion updateFound = null; try { - ModEntryModel response = client.GetModInfo(new[] { new ModSearchEntryModel("Pathoschild.SMAPI", new[] { $"GitHub:{this.Settings.GitHubProjectName}" }) }).Single().Value; - ISemanticVersion latestStable = response.Main?.Version; - ISemanticVersion latestBeta = response.Optional?.Version; + // fetch update check + ModEntryModel response = client.GetModInfo(new[] { new ModSearchEntryModel("Pathoschild.SMAPI", Constants.ApiVersion, new[] { $"GitHub:{this.Settings.GitHubProjectName}" }) }, apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform).Single().Value; + if (response.SuggestedUpdate != null) + this.Monitor.Log($"You can update SMAPI to {response.SuggestedUpdate.Version}: {Constants.HomePageUrl}", LogLevel.Alert); + else + this.Monitor.Log(" SMAPI okay.", LogLevel.Trace); - if (latestStable == null && response.Errors.Any()) + // show errors + if (response.Errors.Any()) { this.Monitor.Log("Couldn't check for a new version of SMAPI. This won't affect your game, but you may not be notified of new versions if this keeps happening.", LogLevel.Warn); this.Monitor.Log($"Error: {string.Join("\n", response.Errors)}", LogLevel.Trace); } - else if (this.IsValidUpdate(Constants.ApiVersion, latestBeta, this.Settings.UseBetaChannel)) - { - updateFound = latestBeta; - this.Monitor.Log($"You can update SMAPI to {latestBeta}: {Constants.HomePageUrl}", LogLevel.Alert); - } - else if (this.IsValidUpdate(Constants.ApiVersion, latestStable, this.Settings.UseBetaChannel)) - { - updateFound = latestStable; - this.Monitor.Log($"You can update SMAPI to {latestStable}: {Constants.HomePageUrl}", LogLevel.Alert); - } - else - this.Monitor.Log(" SMAPI okay.", LogLevel.Trace); } catch (Exception ex) { @@ -646,12 +638,12 @@ namespace StardewModdingAPI.Framework .GetUpdateKeys(validOnly: true) .Select(p => p.ToString()) .ToArray(); - searchMods.Add(new ModSearchEntryModel(mod.Manifest.UniqueID, updateKeys.ToArray())); + searchMods.Add(new ModSearchEntryModel(mod.Manifest.UniqueID, mod.Manifest.Version, updateKeys.ToArray(), isBroken: mod.Status == ModMetadataStatus.Failed)); } // fetch results this.Monitor.Log($" Checking for updates to {searchMods.Count} mods...", LogLevel.Trace); - IDictionary results = client.GetModInfo(searchMods.ToArray()); + IDictionary results = client.GetModInfo(searchMods.ToArray(), apiVersion: Constants.ApiVersion, gameVersion: Constants.GameVersion, platform: Constants.Platform); // extract update alerts & errors var updates = new List>(); @@ -672,20 +664,9 @@ namespace StardewModdingAPI.Framework ); } - // parse versions - bool useBetaInfo = result.HasBetaInfo && Constants.ApiVersion.IsPrerelease(); - ISemanticVersion localVersion = mod.DataRecord?.GetLocalVersionForUpdateChecks(mod.Manifest.Version) ?? mod.Manifest.Version; - ISemanticVersion latestVersion = mod.DataRecord?.GetRemoteVersionForUpdateChecks(result.Main?.Version) ?? result.Main?.Version; - ISemanticVersion optionalVersion = mod.DataRecord?.GetRemoteVersionForUpdateChecks(result.Optional?.Version) ?? result.Optional?.Version; - ISemanticVersion unofficialVersion = useBetaInfo ? result.UnofficialForBeta?.Version : result.Unofficial?.Version; - - // show update alerts - if (this.IsValidUpdate(localVersion, latestVersion, useBetaChannel: true)) - updates.Add(Tuple.Create(mod, latestVersion, result.Main?.Url)); - else if (this.IsValidUpdate(localVersion, optionalVersion, useBetaChannel: localVersion.IsPrerelease())) - updates.Add(Tuple.Create(mod, optionalVersion, result.Optional?.Url)); - else if (this.IsValidUpdate(localVersion, unofficialVersion, useBetaChannel: mod.Status == ModMetadataStatus.Failed)) - updates.Add(Tuple.Create(mod, unofficialVersion, useBetaInfo ? result.UnofficialForBeta?.Url : result.Unofficial?.Url)); + // handle update + if (result.SuggestedUpdate != null) + updates.Add(Tuple.Create(mod, result.SuggestedUpdate.Version, result.SuggestedUpdate.Url)); } // show update errors @@ -720,18 +701,6 @@ namespace StardewModdingAPI.Framework }).Start(); } - /// Get whether a given version should be offered to the user as an update. - /// The current semantic version. - /// The target semantic version. - /// Whether the user enabled the beta channel and should be offered prerelease updates. - private bool IsValidUpdate(ISemanticVersion currentVersion, ISemanticVersion newVersion, bool useBetaChannel) - { - return - newVersion != null - && newVersion.IsNewerThan(currentVersion) - && (useBetaChannel || !newVersion.IsPrerelease()); - } - /// Create a directory path if it doesn't exist. /// The directory path. private void VerifyPath(string path) -- cgit From 7a2fc8471fe31f560ddcf5e5005b92b0cd0a7c57 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 14 Aug 2019 19:52:04 -0400 Subject: update for draw changes in SDV 1.4 (#638) --- src/SMAPI/Framework/SGame.cs | 179 ++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 104 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 13858fc5..cdd7437a 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -815,12 +815,20 @@ namespace StardewModdingAPI.Framework { var events = this.Events; + // from Game1.Draw + RenderTarget2D target_screen = (RenderTarget2D)null; + if ((double)Game1.options.zoomLevel != 1.0) + target_screen = this.screen; + + // from Game1._draw if (Game1._newDayTask != null) + { this.GraphicsDevice.Clear(Game1.bgColor); + } else { - if ((double)Game1.options.zoomLevel != 1.0) - this.GraphicsDevice.SetRenderTarget(this.screen); + if (target_screen != null) + this.GraphicsDevice.SetRenderTarget(target_screen); if (this.IsSaving) { this.GraphicsDevice.Clear(Game1.bgColor); @@ -874,12 +882,12 @@ namespace StardewModdingAPI.Framework events.Rendered.RaiseEmpty(); Game1.spriteBatch.End(); this.drawOverlays(Game1.spriteBatch); - if ((double)Game1.options.zoomLevel != 1.0) + if (target_screen != null) { this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.Draw((Texture2D)target_screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(target_screen.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } if (Game1.overlayMenu == null) @@ -892,9 +900,9 @@ namespace StardewModdingAPI.Framework { Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); events.Rendering.RaiseEmpty(); - Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3685"), new Vector2(16f, 16f), Color.HotPink); - Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Color(0, (int)byte.MaxValue, 0)); - Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Color.White); + Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3685"), new Vector2(16f, 16f), Microsoft.Xna.Framework.Color.HotPink); + Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.content.LoadString("Strings\\StringsFromCSFiles:Game1.cs.3686"), new Vector2(16f, 32f), new Microsoft.Xna.Framework.Color(0, (int)byte.MaxValue, 0)); + Game1.spriteBatch.DrawString(Game1.dialogueFont, Game1.parseText(Game1.errorMessage, Game1.dialogueFont, Game1.graphics.GraphicsDevice.Viewport.Width), new Vector2(16f, 48f), Microsoft.Xna.Framework.Color.White); events.Rendered.RaiseEmpty(); Game1.spriteBatch.End(); } @@ -904,16 +912,16 @@ namespace StardewModdingAPI.Framework if (Game1.globalFade && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) { Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * (Game1.gameMode == (byte)0 ? 1f - Game1.fadeToBlackAlpha : Game1.fadeToBlackAlpha)); + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Microsoft.Xna.Framework.Color.Black * (Game1.gameMode == (byte)0 ? 1f - Game1.fadeToBlackAlpha : Game1.fadeToBlackAlpha)); Game1.spriteBatch.End(); } this.drawOverlays(Game1.spriteBatch); - if ((double)Game1.options.zoomLevel == 1.0) + if (target_screen == null) return; this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.Draw((Texture2D)target_screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(target_screen.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } else if (Game1.showingEndOfNightStuff) @@ -937,12 +945,12 @@ namespace StardewModdingAPI.Framework events.Rendered.RaiseEmpty(); Game1.spriteBatch.End(); this.drawOverlays(Game1.spriteBatch); - if ((double)Game1.options.zoomLevel == 1.0) + if (target_screen == null) return; this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.Draw((Texture2D)target_screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(target_screen.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } else if (Game1.gameMode == (byte)6 || Game1.gameMode == (byte)3 && Game1.currentLocation == null) @@ -963,12 +971,12 @@ namespace StardewModdingAPI.Framework events.Rendered.RaiseEmpty(); Game1.spriteBatch.End(); this.drawOverlays(Game1.spriteBatch); - if ((double)Game1.options.zoomLevel != 1.0) + if (target_screen != null) { this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); - Game1.spriteBatch.Draw((Texture2D)this.screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screen.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + Game1.spriteBatch.Draw((Texture2D)target_screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(target_screen.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } if (Game1.overlayMenu != null) @@ -995,12 +1003,12 @@ namespace StardewModdingAPI.Framework if (Game1.drawLighting) { this.GraphicsDevice.SetRenderTarget(Game1.lightmap); - this.GraphicsDevice.Clear(Color.White * 0.0f); + this.GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.White * 0.0f); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); if (++batchOpens == 1) events.Rendering.RaiseEmpty(); - Color color1 = !Game1.currentLocation.Name.StartsWith("UndergroundMine") || !(Game1.currentLocation is MineShaft) ? (Game1.ambientLight.Equals(Color.White) || Game1.isRaining && (bool)((NetFieldBase)Game1.currentLocation.isOutdoors) ? Game1.outdoorLight : Game1.ambientLight) : (Game1.currentLocation as MineShaft).getLightingColor(gameTime); - Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, color1); + Microsoft.Xna.Framework.Color color = !Game1.currentLocation.Name.StartsWith("UndergroundMine") || !(Game1.currentLocation is MineShaft) ? (Game1.ambientLight.Equals(Microsoft.Xna.Framework.Color.White) || Game1.isRaining && (bool)((NetFieldBase)Game1.currentLocation.isOutdoors) ? Game1.outdoorLight : Game1.ambientLight) : (Game1.currentLocation as MineShaft).getLightingColor(gameTime); + Game1.spriteBatch.Draw(Game1.staminaRect, Game1.lightmap.Bounds, color); for (int index = 0; index < Game1.currentLightSources.Count; ++index) { LightSource lightSource = Game1.currentLightSources.ElementAt(index); @@ -1011,23 +1019,10 @@ namespace StardewModdingAPI.Framework continue; } if (Utility.isOnScreen((Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position), (int)((double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) * 64.0 * 4.0))) - { - SpriteBatch spriteBatch = Game1.spriteBatch; - Texture2D lightTexture = Game1.currentLightSources.ElementAt(index).lightTexture; - Vector2 position = Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2); - Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds); - Color color2 = (Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color); - Microsoft.Xna.Framework.Rectangle bounds = Game1.currentLightSources.ElementAt(index).lightTexture.Bounds; - double x = (double)bounds.Center.X; - bounds = Game1.currentLightSources.ElementAt(index).lightTexture.Bounds; - double y = (double)bounds.Center.Y; - Vector2 origin = new Vector2((float)x, (float)y); - double num = (double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (double)(Game1.options.lightingQuality / 2); - spriteBatch.Draw(lightTexture, position, sourceRectangle, color2, 0.0f, origin, (float)num, SpriteEffects.None, 0.9f); - } + Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Microsoft.Xna.Framework.Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); } Game1.spriteBatch.End(); - this.GraphicsDevice.SetRenderTarget((double)Game1.options.zoomLevel == 1.0 ? (RenderTarget2D)null : this.screen); + this.GraphicsDevice.SetRenderTarget(target_screen); } if (Game1.bloomDay && Game1.bloom != null) Game1.bloom.BeginDraw(); @@ -1065,7 +1060,7 @@ namespace StardewModdingAPI.Framework foreach (NPC character in Game1.currentLocation.characters) { if (!(bool)((NetFieldBase)character.swimming) && !character.HideShadow && (!character.IsInvisible && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(character.getTileLocation()))) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, character.Position + new Vector2((float)(character.Sprite.SpriteWidth * 4) / 2f, (float)(character.GetBoundingBox().Height + (character.IsMonster ? 0 : 12)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)character.yJumpOffset / 40.0) * (float)((NetFieldBase)character.scale), SpriteEffects.None, Math.Max(0.0f, (float)character.getStandingY() / 10000f) - 1E-06f); + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, character.Position + new Vector2((float)(character.Sprite.SpriteWidth * 4) / 2f, (float)(character.GetBoundingBox().Height + (character.IsMonster ? 0 : 12)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)character.yJumpOffset / 40.0) * (float)((NetFieldBase)character.scale), SpriteEffects.None, Math.Max(0.0f, (float)character.getStandingY() / 10000f) - 1E-06f); } } else @@ -1073,26 +1068,13 @@ namespace StardewModdingAPI.Framework foreach (NPC actor in Game1.CurrentEvent.actors) { if (!(bool)((NetFieldBase)actor.swimming) && !actor.HideShadow && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(actor.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, actor.Position + new Vector2((float)(actor.Sprite.SpriteWidth * 4) / 2f, (float)(actor.GetBoundingBox().Height + (actor.IsMonster ? 0 : (actor.Sprite.SpriteHeight <= 16 ? -4 : 12))))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)actor.yJumpOffset / 40.0) * (float)((NetFieldBase)actor.scale), SpriteEffects.None, Math.Max(0.0f, (float)actor.getStandingY() / 10000f) - 1E-06f); + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, actor.Position + new Vector2((float)(actor.Sprite.SpriteWidth * 4) / 2f, (float)(actor.GetBoundingBox().Height + (actor.IsMonster ? 0 : (actor.Sprite.SpriteHeight <= 16 ? -4 : 12))))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)actor.yJumpOffset / 40.0) * (float)((NetFieldBase)actor.scale), SpriteEffects.None, Math.Max(0.0f, (float)actor.getStandingY() / 10000f) - 1E-06f); } } foreach (Farmer farmerShadow in this._farmerShadows) { if (!Game1.multiplayer.isDisconnecting(farmerShadow.UniqueMultiplayerID) && !(bool)((NetFieldBase)farmerShadow.swimming) && !farmerShadow.isRidingHorse() && (Game1.currentLocation == null || !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(farmerShadow.getTileLocation()))) - { - SpriteBatch spriteBatch = Game1.spriteBatch; - Texture2D shadowTexture = Game1.shadowTexture; - Vector2 local = Game1.GlobalToLocal(farmerShadow.Position + new Vector2(32f, 24f)); - Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); - Color white = Color.White; - Microsoft.Xna.Framework.Rectangle bounds = Game1.shadowTexture.Bounds; - double x = (double)bounds.Center.X; - bounds = Game1.shadowTexture.Bounds; - double y = (double)bounds.Center.Y; - Vector2 origin = new Vector2((float)x, (float)y); - double num = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); - spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, 0.0f, origin, (float)num, SpriteEffects.None, 0.0f); - } + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(farmerShadow.Position + new Vector2(32f, 24f)), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5)), SpriteEffects.None, 0.0f); } } Layer layer = Game1.currentLocation.Map.GetLayer("Buildings"); @@ -1107,7 +1089,7 @@ namespace StardewModdingAPI.Framework foreach (NPC character in Game1.currentLocation.characters) { if (!(bool)((NetFieldBase)character.swimming) && !character.HideShadow && (!(bool)((NetFieldBase)character.isInvisible) && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(character.getTileLocation()))) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, character.Position + new Vector2((float)(character.Sprite.SpriteWidth * 4) / 2f, (float)(character.GetBoundingBox().Height + (character.IsMonster ? 0 : 12)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)character.yJumpOffset / 40.0) * (float)((NetFieldBase)character.scale), SpriteEffects.None, Math.Max(0.0f, (float)character.getStandingY() / 10000f) - 1E-06f); + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, character.Position + new Vector2((float)(character.Sprite.SpriteWidth * 4) / 2f, (float)(character.GetBoundingBox().Height + (character.IsMonster ? 0 : 12)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)character.yJumpOffset / 40.0) * (float)((NetFieldBase)character.scale), SpriteEffects.None, Math.Max(0.0f, (float)character.getStandingY() / 10000f) - 1E-06f); } } else @@ -1115,34 +1097,20 @@ namespace StardewModdingAPI.Framework foreach (NPC actor in Game1.CurrentEvent.actors) { if (!(bool)((NetFieldBase)actor.swimming) && !actor.HideShadow && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(actor.getTileLocation())) - Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, actor.Position + new Vector2((float)(actor.Sprite.SpriteWidth * 4) / 2f, (float)(actor.GetBoundingBox().Height + (actor.IsMonster ? 0 : 12)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)actor.yJumpOffset / 40.0) * (float)((NetFieldBase)actor.scale), SpriteEffects.None, Math.Max(0.0f, (float)actor.getStandingY() / 10000f) - 1E-06f); + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, actor.Position + new Vector2((float)(actor.Sprite.SpriteWidth * 4) / 2f, (float)(actor.GetBoundingBox().Height + (actor.IsMonster ? 0 : 12)))), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 + (double)actor.yJumpOffset / 40.0) * (float)((NetFieldBase)actor.scale), SpriteEffects.None, Math.Max(0.0f, (float)actor.getStandingY() / 10000f) - 1E-06f); } } foreach (Farmer farmerShadow in this._farmerShadows) { - float num1 = Math.Max(0.0001f, farmerShadow.getDrawLayer() + 0.00011f) - 0.0001f; + float layerDepth = Math.Max(0.0001f, farmerShadow.getDrawLayer() + 0.00011f) - 0.0001f; if (!(bool)((NetFieldBase)farmerShadow.swimming) && !farmerShadow.isRidingHorse() && (Game1.currentLocation != null && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(farmerShadow.getTileLocation()))) - { - SpriteBatch spriteBatch = Game1.spriteBatch; - Texture2D shadowTexture = Game1.shadowTexture; - Vector2 local = Game1.GlobalToLocal(farmerShadow.Position + new Vector2(32f, 24f)); - Microsoft.Xna.Framework.Rectangle? sourceRectangle = new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds); - Color white = Color.White; - Microsoft.Xna.Framework.Rectangle bounds = Game1.shadowTexture.Bounds; - double x = (double)bounds.Center.X; - bounds = Game1.shadowTexture.Bounds; - double y = (double)bounds.Center.Y; - Vector2 origin = new Vector2((float)x, (float)y); - double num2 = 4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5); - double num3 = (double)num1; - spriteBatch.Draw(shadowTexture, local, sourceRectangle, white, 0.0f, origin, (float)num2, SpriteEffects.None, (float)num3); - } + Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(farmerShadow.Position + new Vector2(32f, 24f)), new Microsoft.Xna.Framework.Rectangle?(Game1.shadowTexture.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)(4.0 - (!farmerShadow.running && !farmerShadow.UsingTool || farmerShadow.FarmerSprite.currentAnimationIndex <= 1 ? 0.0 : (double)Math.Abs(FarmerRenderer.featureYOffsetPerFrame[farmerShadow.FarmerSprite.CurrentFrame]) * 0.5)), SpriteEffects.None, layerDepth); } } if ((Game1.eventUp || Game1.killScreen) && (!Game1.killScreen && Game1.currentLocation.currentEvent != null)) Game1.currentLocation.currentEvent.draw(Game1.spriteBatch); if (Game1.player.currentUpgrade != null && Game1.player.currentUpgrade.daysLeftTillUpgradeDone <= 3 && Game1.currentLocation.Name.Equals("Farm")) - Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), new Microsoft.Xna.Framework.Rectangle?(Game1.player.currentUpgrade.getSourceRectangle()), Color.White, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, (float)(((double)Game1.player.currentUpgrade.positionOfCarpenter.Y + 48.0) / 10000.0)); + Game1.spriteBatch.Draw(Game1.player.currentUpgrade.workerTexture, Game1.GlobalToLocal(Game1.viewport, Game1.player.currentUpgrade.positionOfCarpenter), new Microsoft.Xna.Framework.Rectangle?(Game1.player.currentUpgrade.getSourceRectangle()), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, (float)(((double)Game1.player.currentUpgrade.positionOfCarpenter.Y + 48.0) / 10000.0)); Game1.currentLocation.draw(Game1.spriteBatch); foreach (Vector2 key in Game1.crabPotOverlayTiles.Keys) { @@ -1163,12 +1131,12 @@ namespace StardewModdingAPI.Framework if (Game1.currentLocation.Name.Equals("Farm")) this.drawFarmBuildings(); if (Game1.tvStation >= 0) - Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(400f, 160f)), new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(Game1.tvStation * 24, 0, 24, 15)), Color.White, 0.0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f); + Game1.spriteBatch.Draw(Game1.tvStationTexture, Game1.GlobalToLocal(Game1.viewport, new Vector2(400f, 160f)), new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(Game1.tvStation * 24, 0, 24, 15)), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, 4f, SpriteEffects.None, 1E-08f); if (Game1.panMode) { - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((int)Math.Floor((double)(Game1.getOldMouseX() + Game1.viewport.X) / 64.0) * 64 - Game1.viewport.X, (int)Math.Floor((double)(Game1.getOldMouseY() + Game1.viewport.Y) / 64.0) * 64 - Game1.viewport.Y, 64, 64), Color.Lime * 0.75f); + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((int)Math.Floor((double)(Game1.getOldMouseX() + Game1.viewport.X) / 64.0) * 64 - Game1.viewport.X, (int)Math.Floor((double)(Game1.getOldMouseY() + Game1.viewport.Y) / 64.0) * 64 - Game1.viewport.Y, 64, 64), Microsoft.Xna.Framework.Color.Lime * 0.75f); foreach (Warp warp in (NetList>)Game1.currentLocation.warps) - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(warp.X * 64 - Game1.viewport.X, warp.Y * 64 - Game1.viewport.Y, 64, 64), Color.Red * 0.75f); + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle(warp.X * 64 - Game1.viewport.X, warp.Y * 64 - Game1.viewport.Y, 64, 64), Microsoft.Xna.Framework.Color.Red * 0.75f); } Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch); Game1.currentLocation.Map.GetLayer("Front").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, 4); @@ -1190,7 +1158,7 @@ namespace StardewModdingAPI.Framework } if ((double)Game1.toolHold > 400.0 && Game1.player.CurrentTool.UpgradeLevel >= 1 && Game1.player.canReleaseTool) { - Color color = Color.White; + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.White; switch ((int)((double)Game1.toolHold / 600.0) + 2) { case 1: @@ -1206,7 +1174,7 @@ namespace StardewModdingAPI.Framework color = Tool.iridiumColor; break; } - Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64) - 2, (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607) + 4, 12), Color.Black); + Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64) - 2, (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607) + 4, 12), Microsoft.Xna.Framework.Color.Black); Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64), (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607), 8), color); } bool flag = Game1.viewport.X > -Game1.viewport.Width; @@ -1223,7 +1191,7 @@ namespace StardewModdingAPI.Framework Texture2D fadeToBlackRect = Game1.fadeToBlackRect; viewport = Game1.graphics.GraphicsDevice.Viewport; Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; - Color color = Color.Black * Game1.currentLocation.LightLevel; + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.Black * Game1.currentLocation.LightLevel; spriteBatch.Draw(fadeToBlackRect, bounds, color); } if (Game1.screenGlow) @@ -1232,7 +1200,7 @@ namespace StardewModdingAPI.Framework Texture2D fadeToBlackRect = Game1.fadeToBlackRect; viewport = Game1.graphics.GraphicsDevice.Viewport; Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; - Color color = Game1.screenGlowColor * Game1.screenGlowAlpha; + Microsoft.Xna.Framework.Color color = Game1.screenGlowColor * Game1.screenGlowAlpha; spriteBatch.Draw(fadeToBlackRect, bounds, color); } Game1.currentLocation.drawAboveAlwaysFrontLayer(Game1.spriteBatch); @@ -1241,7 +1209,7 @@ namespace StardewModdingAPI.Framework if (Game1.isRaining && Game1.currentLocation.IsOutdoors && (!Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit)) && (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2((float)(Game1.viewport.X / 64), (float)(Game1.viewport.Y / 64))))) { for (int index = 0; index < Game1.rainDrops.Length; ++index) - Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[index].position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Color.White); + Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[index].position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Microsoft.Xna.Framework.Color.White); } Game1.spriteBatch.End(); Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); @@ -1257,7 +1225,7 @@ namespace StardewModdingAPI.Framework localPosition.Y += 32f; else if (actor.Gender == 1) localPosition.Y += 10f; - Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, localPosition, new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(actor.CurrentEmoteIndex * 16 % Game1.emoteSpriteSheet.Width, actor.CurrentEmoteIndex * 16 / Game1.emoteSpriteSheet.Width * 16, 16, 16)), Color.White, 0.0f, Vector2.Zero, 4f, SpriteEffects.None, (float)actor.getStandingY() / 10000f); + Game1.spriteBatch.Draw(Game1.emoteSpriteSheet, localPosition, new Microsoft.Xna.Framework.Rectangle?(new Microsoft.Xna.Framework.Rectangle(actor.CurrentEmoteIndex * 16 % Game1.emoteSpriteSheet.Width, actor.CurrentEmoteIndex * 16 / Game1.emoteSpriteSheet.Width * 16, 16, 16)), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, 4f, SpriteEffects.None, (float)actor.getStandingY() / 10000f); } } } @@ -1265,14 +1233,14 @@ namespace StardewModdingAPI.Framework if (Game1.drawLighting) { Game1.spriteBatch.Begin(SpriteSortMode.Deferred, this.lightingBlend, SamplerState.LinearClamp, (DepthStencilState)null, (RasterizerState)null); - Game1.spriteBatch.Draw((Texture2D)Game1.lightmap, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(Game1.lightmap.Bounds), Color.White, 0.0f, Vector2.Zero, (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 1f); + Game1.spriteBatch.Draw((Texture2D)Game1.lightmap, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(Game1.lightmap.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 1f); if (Game1.isRaining && (bool)((NetFieldBase)Game1.currentLocation.isOutdoors) && !(Game1.currentLocation is Desert)) { SpriteBatch spriteBatch = Game1.spriteBatch; Texture2D staminaRect = Game1.staminaRect; viewport = Game1.graphics.GraphicsDevice.Viewport; Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; - Color color = Color.OrangeRed * 0.45f; + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.OrangeRed * 0.45f; spriteBatch.Draw(staminaRect, bounds, color); } Game1.spriteBatch.End(); @@ -1298,7 +1266,7 @@ namespace StardewModdingAPI.Framework viewport = Game1.graphics.GraphicsDevice.Viewport; int height = viewport.Height; Microsoft.Xna.Framework.Rectangle destinationRectangle = new Microsoft.Xna.Framework.Rectangle(x, y, 1, height); - Color color = Color.Red * 0.5f; + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.Red * 0.5f; spriteBatch.Draw(staminaRect, destinationRectangle, color); num3 += 64; } @@ -1320,7 +1288,7 @@ namespace StardewModdingAPI.Framework viewport = Game1.graphics.GraphicsDevice.Viewport; int width = viewport.Width; Microsoft.Xna.Framework.Rectangle destinationRectangle = new Microsoft.Xna.Framework.Rectangle(x, y, width, 1); - Color color = Color.Red * 0.5f; + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.Red * 0.5f; spriteBatch.Draw(staminaRect, destinationRectangle, color); num5 += 64f; } @@ -1328,9 +1296,9 @@ namespace StardewModdingAPI.Framework break; } } - if (Game1.currentBillboard != 0) + if (Game1.currentBillboard != 0 && !this.takingMapScreenshot) this.drawBillboard(); - if (!Game1.eventUp && Game1.farmEvent == null && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && Game1.isOutdoorMapSmallerThanViewport()) + if (!Game1.eventUp && Game1.farmEvent == null && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && (!this.takingMapScreenshot && Game1.isOutdoorMapSmallerThanViewport())) { SpriteBatch spriteBatch1 = Game1.spriteBatch; Texture2D fadeToBlackRect1 = Game1.fadeToBlackRect; @@ -1338,7 +1306,7 @@ namespace StardewModdingAPI.Framework viewport = Game1.graphics.GraphicsDevice.Viewport; int height1 = viewport.Height; Microsoft.Xna.Framework.Rectangle destinationRectangle1 = new Microsoft.Xna.Framework.Rectangle(0, 0, width1, height1); - Color black1 = Color.Black; + Microsoft.Xna.Framework.Color black1 = Microsoft.Xna.Framework.Color.Black; spriteBatch1.Draw(fadeToBlackRect1, destinationRectangle1, black1); SpriteBatch spriteBatch2 = Game1.spriteBatch; Texture2D fadeToBlackRect2 = Game1.fadeToBlackRect; @@ -1348,10 +1316,10 @@ namespace StardewModdingAPI.Framework viewport = Game1.graphics.GraphicsDevice.Viewport; int height2 = viewport.Height; Microsoft.Xna.Framework.Rectangle destinationRectangle2 = new Microsoft.Xna.Framework.Rectangle(x, 0, width2, height2); - Color black2 = Color.Black; + Microsoft.Xna.Framework.Color black2 = Microsoft.Xna.Framework.Color.Black; spriteBatch2.Draw(fadeToBlackRect2, destinationRectangle2, black2); } - if ((Game1.displayHUD || Game1.eventUp) && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && (!Game1.freezeControls && !Game1.panMode && !Game1.HostPaused)) + if ((Game1.displayHUD || Game1.eventUp) && (Game1.currentBillboard == 0 && Game1.gameMode == (byte)3) && (!Game1.freezeControls && !Game1.panMode && (!Game1.HostPaused && !this.takingMapScreenshot))) { events.RenderingHud.RaiseEmpty(); this.drawHUD(); @@ -1361,7 +1329,7 @@ namespace StardewModdingAPI.Framework { FarmEvent farmEvent = Game1.farmEvent; } - if (Game1.hudMessages.Count > 0) + if (Game1.hudMessages.Count > 0 && !this.takingMapScreenshot) { for (int i = Game1.hudMessages.Count - 1; i >= 0; --i) Game1.hudMessages[i].draw(Game1.spriteBatch, i); @@ -1369,12 +1337,12 @@ namespace StardewModdingAPI.Framework } if (Game1.farmEvent != null) Game1.farmEvent.draw(Game1.spriteBatch); - if (Game1.dialogueUp && !Game1.nameSelectUp && !Game1.messagePause && (Game1.activeClickableMenu == null || !(Game1.activeClickableMenu is DialogueBox))) + if (Game1.dialogueUp && !Game1.nameSelectUp && !Game1.messagePause && ((Game1.activeClickableMenu == null || !(Game1.activeClickableMenu is DialogueBox)) && !this.takingMapScreenshot)) this.drawDialogueBox(); - if (Game1.progressBar) + if (Game1.progressBar && !this.takingMapScreenshot) { - Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, Game1.dialogueWidth, 32), Color.LightGray); - Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, (int)((double)Game1.pauseAccumulator / (double)Game1.pauseTime * (double)Game1.dialogueWidth), 32), Color.DimGray); + Game1.spriteBatch.Draw(Game1.fadeToBlackRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, Game1.dialogueWidth, 32), Microsoft.Xna.Framework.Color.LightGray); + Game1.spriteBatch.Draw(Game1.staminaRect, new Microsoft.Xna.Framework.Rectangle((Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Width - Game1.dialogueWidth) / 2, Game1.graphics.GraphicsDevice.Viewport.GetTitleSafeArea().Bottom - 128, (int)((double)Game1.pauseAccumulator / (double)Game1.pauseTime * (double)Game1.dialogueWidth), 32), Microsoft.Xna.Framework.Color.DimGray); } if (Game1.eventUp && Game1.currentLocation != null && Game1.currentLocation.currentEvent != null) Game1.currentLocation.currentEvent.drawAfterMap(Game1.spriteBatch); @@ -1384,19 +1352,19 @@ namespace StardewModdingAPI.Framework Texture2D staminaRect = Game1.staminaRect; viewport = Game1.graphics.GraphicsDevice.Viewport; Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; - Color color = Color.Blue * 0.2f; + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.Blue * 0.2f; spriteBatch.Draw(staminaRect, bounds, color); } - if ((Game1.fadeToBlack || Game1.globalFade) && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) + if ((Game1.fadeToBlack || Game1.globalFade) && !Game1.menuUp && ((!Game1.nameSelectUp || Game1.messagePause) && !this.takingMapScreenshot)) { SpriteBatch spriteBatch = Game1.spriteBatch; Texture2D fadeToBlackRect = Game1.fadeToBlackRect; viewport = Game1.graphics.GraphicsDevice.Viewport; Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; - Color color = Color.Black * (Game1.gameMode == (byte)0 ? 1f - Game1.fadeToBlackAlpha : Game1.fadeToBlackAlpha); + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.Black * (Game1.gameMode == (byte)0 ? 1f - Game1.fadeToBlackAlpha : Game1.fadeToBlackAlpha); spriteBatch.Draw(fadeToBlackRect, bounds, color); } - else if ((double)Game1.flashAlpha > 0.0) + else if ((double)Game1.flashAlpha > 0.0 && !this.takingMapScreenshot) { if (Game1.options.screenFlash) { @@ -1404,15 +1372,18 @@ namespace StardewModdingAPI.Framework Texture2D fadeToBlackRect = Game1.fadeToBlackRect; viewport = Game1.graphics.GraphicsDevice.Viewport; Microsoft.Xna.Framework.Rectangle bounds = viewport.Bounds; - Color color = Color.White * Math.Min(1f, Game1.flashAlpha); + Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.White * Math.Min(1f, Game1.flashAlpha); spriteBatch.Draw(fadeToBlackRect, bounds, color); } Game1.flashAlpha -= 0.1f; } - if ((Game1.messagePause || Game1.globalFade) && Game1.dialogueUp) + if ((Game1.messagePause || Game1.globalFade) && (Game1.dialogueUp && !this.takingMapScreenshot)) this.drawDialogueBox(); - foreach (TemporaryAnimatedSprite overlayTempSprite in Game1.screenOverlayTempSprites) - overlayTempSprite.draw(Game1.spriteBatch, true, 0, 0, 1f); + if (!this.takingMapScreenshot) + { + foreach (TemporaryAnimatedSprite overlayTempSprite in Game1.screenOverlayTempSprites) + overlayTempSprite.draw(Game1.spriteBatch, true, 0, 0, 1f); + } if (Game1.debugMode) { StringBuilder debugStringBuilder = Game1._debugStringBuilder; @@ -1443,11 +1414,11 @@ namespace StardewModdingAPI.Framework debugStringBuilder.Append(Game1.getMouseY() + Game1.viewport.Y); debugStringBuilder.Append(" debugOutput: "); debugStringBuilder.Append(Game1.debugOutput); - Game1.spriteBatch.DrawString(Game1.smallFont, debugStringBuilder, new Vector2((float)this.GraphicsDevice.Viewport.GetTitleSafeArea().X, (float)(this.GraphicsDevice.Viewport.GetTitleSafeArea().Y + Game1.smallFont.LineSpacing * 8)), Color.Red, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + Game1.spriteBatch.DrawString(Game1.smallFont, debugStringBuilder, new Vector2((float)this.GraphicsDevice.Viewport.GetTitleSafeArea().X, (float)(this.GraphicsDevice.Viewport.GetTitleSafeArea().Y + Game1.smallFont.LineSpacing * 8)), Microsoft.Xna.Framework.Color.Red, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); } - if (Game1.showKeyHelp) - Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(64f, (float)(Game1.viewport.Height - 64 - (Game1.dialogueUp ? 192 + (Game1.isQuestion ? Game1.questionChoices.Count * 64 : 0) : 0)) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Color.LightGray, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); - if (Game1.activeClickableMenu != null) + if (Game1.showKeyHelp && !this.takingMapScreenshot) + Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(64f, (float)(Game1.viewport.Height - 64 - (Game1.dialogueUp ? 192 + (Game1.isQuestion ? Game1.questionChoices.Count * 64 : 0) : 0)) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Microsoft.Xna.Framework.Color.LightGray, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f); + if (Game1.activeClickableMenu != null && !this.takingMapScreenshot) { try { @@ -1463,9 +1434,9 @@ namespace StardewModdingAPI.Framework } else if (Game1.farmEvent != null) Game1.farmEvent.drawAboveEverything(Game1.spriteBatch); - if (Game1.emoteMenu != null) + if (Game1.emoteMenu != null && !this.takingMapScreenshot) Game1.emoteMenu.draw(Game1.spriteBatch); - if (Game1.HostPaused) + if (Game1.HostPaused && !this.takingMapScreenshot) { string s = Game1.content.LoadString("Strings\\StringsFromCSFiles:DayTimeMoneyBox.cs.10378"); SpriteText.drawStringWithScrollBackground(Game1.spriteBatch, s, 96, 32, "", 1f, -1, SpriteText.ScrollTextAlignment.Left); -- cgit From 6e46990ed116e55e95de58047753b4fe1c3dcaf6 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 15 Aug 2019 22:26:14 -0400 Subject: update for more draw changes (#638) --- src/SMAPI/Framework/SGame.cs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index cdd7437a..0d518564 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -857,7 +857,7 @@ namespace StardewModdingAPI.Framework Game1.overlayMenu.draw(Game1.spriteBatch); Game1.spriteBatch.End(); } - this.renderScreenBuffer(); + this.renderScreenBuffer(target_screen); } else { @@ -1177,11 +1177,26 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64) - 2, (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607) + 4, 12), Microsoft.Xna.Framework.Color.Black); Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64), (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607), 8), color); } - bool flag = Game1.viewport.X > -Game1.viewport.Width; - if (((!Game1.isDebrisWeather || !Game1.currentLocation.IsOutdoors || (bool)((NetFieldBase)Game1.currentLocation.ignoreDebrisWeather) ? 0 : (!Game1.currentLocation.Name.Equals("Desert") ? 1 : 0)) & (flag ? 1 : 0)) != 0) + if (Game1.isDebrisWeather && Game1.currentLocation.IsOutdoors && (!(bool)((NetFieldBase)Game1.currentLocation.ignoreDebrisWeather) && !Game1.currentLocation.Name.Equals("Desert"))) { - foreach (WeatherDebris weatherDebris in Game1.debrisWeather) - weatherDebris.draw(Game1.spriteBatch); + if (this.takingMapScreenshot) + { + if (Game1.debrisWeather != null) + { + foreach (WeatherDebris weatherDebris in Game1.debrisWeather) + { + Vector2 position = weatherDebris.position; + weatherDebris.position = new Vector2((float)Game1.random.Next(Game1.viewport.Width - weatherDebris.sourceRect.Width * 3), (float)Game1.random.Next(Game1.viewport.Height - weatherDebris.sourceRect.Height * 3)); + weatherDebris.draw(Game1.spriteBatch); + weatherDebris.position = position; + } + } + } + else if (Game1.viewport.X > -Game1.viewport.Width) + { + foreach (WeatherDebris weatherDebris in Game1.debrisWeather) + weatherDebris.draw(Game1.spriteBatch); + } } if (Game1.farmEvent != null) Game1.farmEvent.draw(Game1.spriteBatch); @@ -1445,7 +1460,7 @@ namespace StardewModdingAPI.Framework events.Rendered.RaiseEmpty(); Game1.spriteBatch.End(); this.drawOverlays(Game1.spriteBatch); - this.renderScreenBuffer(); + this.renderScreenBuffer(target_screen); } } } -- cgit From 02300fcaa8cb434d56f4a31f071b33f0003e0b88 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 10 Sep 2019 20:53:48 -0400 Subject: update for more draw changes (#638) --- src/SMAPI/Framework/SGame.cs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 0d518564..07b06bab 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -1012,14 +1012,17 @@ namespace StardewModdingAPI.Framework for (int index = 0; index < Game1.currentLightSources.Count; ++index) { LightSource lightSource = Game1.currentLightSources.ElementAt(index); - if (lightSource.PlayerID != 0L && lightSource.PlayerID != Game1.player.UniqueMultiplayerID) + if ((!Game1.isDarkOut() || lightSource.lightContext.Value != LightSource.LightContext.WindowLight) && !Game1.isRaining) { - Farmer farmerMaybeOffline = Game1.getFarmerMaybeOffline(lightSource.PlayerID); - if (farmerMaybeOffline == null || farmerMaybeOffline.currentLocation != null && farmerMaybeOffline.currentLocation.Name != Game1.currentLocation.Name || (bool)((NetFieldBase)farmerMaybeOffline.hidden)) - continue; + if (lightSource.PlayerID != 0L && lightSource.PlayerID != Game1.player.UniqueMultiplayerID) + { + Farmer farmerMaybeOffline = Game1.getFarmerMaybeOffline(lightSource.PlayerID); + if (farmerMaybeOffline == null || farmerMaybeOffline.currentLocation != null && farmerMaybeOffline.currentLocation.Name != Game1.currentLocation.Name || (bool)((NetFieldBase)farmerMaybeOffline.hidden)) + continue; + } + if (Utility.isOnScreen((Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position), (int)((double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) * 64.0 * 4.0))) + Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Microsoft.Xna.Framework.Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); } - if (Utility.isOnScreen((Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position), (int)((double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) * 64.0 * 4.0))) - Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Microsoft.Xna.Framework.Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); } Game1.spriteBatch.End(); this.GraphicsDevice.SetRenderTarget(target_screen); @@ -1221,10 +1224,21 @@ namespace StardewModdingAPI.Framework Game1.currentLocation.drawAboveAlwaysFrontLayer(Game1.spriteBatch); if (Game1.player.CurrentTool != null && Game1.player.CurrentTool is FishingRod && ((Game1.player.CurrentTool as FishingRod).isTimingCast || (double)(Game1.player.CurrentTool as FishingRod).castingChosenCountdown > 0.0 || ((Game1.player.CurrentTool as FishingRod).fishCaught || (Game1.player.CurrentTool as FishingRod).showingTreasure))) Game1.player.CurrentTool.draw(Game1.spriteBatch); - if (Game1.isRaining && Game1.currentLocation.IsOutdoors && (!Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit)) && (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2((float)(Game1.viewport.X / 64), (float)(Game1.viewport.Y / 64))))) + if (Game1.isRaining && Game1.currentLocation.IsOutdoors && (!Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit))) { - for (int index = 0; index < Game1.rainDrops.Length; ++index) - Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[index].position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Microsoft.Xna.Framework.Color.White); + if (this.takingMapScreenshot) + { + for (int index = 0; index < Game1.rainDrops.Length; ++index) + { + Vector2 position = new Vector2((float)Game1.random.Next(Game1.viewport.Width - 64), (float)Game1.random.Next(Game1.viewport.Height - 64)); + Game1.spriteBatch.Draw(Game1.rainTexture, position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Microsoft.Xna.Framework.Color.White); + } + } + else if (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2((float)(Game1.viewport.X / 64), (float)(Game1.viewport.Y / 64)))) + { + for (int index = 0; index < Game1.rainDrops.Length; ++index) + Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[index].position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Microsoft.Xna.Framework.Color.White); + } } Game1.spriteBatch.End(); Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); -- cgit From 2717ea8cb169767286bf8c24ac2178f2316e893c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 12 Sep 2019 23:56:45 -0400 Subject: update for more draw changes (#638) --- src/SMAPI/Framework/SGame.cs | 42 +++--------------------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 07b06bab..cabbbc3a 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -1012,7 +1012,7 @@ namespace StardewModdingAPI.Framework for (int index = 0; index < Game1.currentLightSources.Count; ++index) { LightSource lightSource = Game1.currentLightSources.ElementAt(index); - if ((!Game1.isDarkOut() || lightSource.lightContext.Value != LightSource.LightContext.WindowLight) && !Game1.isRaining) + if (!Game1.isRaining && !Game1.isDarkOut() || lightSource.lightContext.Value != LightSource.LightContext.WindowLight) { if (lightSource.PlayerID != 0L && lightSource.PlayerID != Game1.player.UniqueMultiplayerID) { @@ -1021,7 +1021,7 @@ namespace StardewModdingAPI.Framework continue; } if (Utility.isOnScreen((Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position), (int)((double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) * 64.0 * 4.0))) - Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Microsoft.Xna.Framework.Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); + Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Microsoft.Xna.Framework.Color) ((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); } } Game1.spriteBatch.End(); @@ -1180,27 +1180,7 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X - 2, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64) - 2, (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607) + 4, 12), Microsoft.Xna.Framework.Color.Black); Game1.spriteBatch.Draw(Game1.littleEffect, new Microsoft.Xna.Framework.Rectangle((int)Game1.player.getLocalPosition(Game1.viewport).X, (int)Game1.player.getLocalPosition(Game1.viewport).Y - (Game1.player.CurrentTool.Name.Equals("Watering Can") ? 0 : 64), (int)((double)Game1.toolHold % 600.0 * 0.0799999982118607), 8), color); } - if (Game1.isDebrisWeather && Game1.currentLocation.IsOutdoors && (!(bool)((NetFieldBase)Game1.currentLocation.ignoreDebrisWeather) && !Game1.currentLocation.Name.Equals("Desert"))) - { - if (this.takingMapScreenshot) - { - if (Game1.debrisWeather != null) - { - foreach (WeatherDebris weatherDebris in Game1.debrisWeather) - { - Vector2 position = weatherDebris.position; - weatherDebris.position = new Vector2((float)Game1.random.Next(Game1.viewport.Width - weatherDebris.sourceRect.Width * 3), (float)Game1.random.Next(Game1.viewport.Height - weatherDebris.sourceRect.Height * 3)); - weatherDebris.draw(Game1.spriteBatch); - weatherDebris.position = position; - } - } - } - else if (Game1.viewport.X > -Game1.viewport.Width) - { - foreach (WeatherDebris weatherDebris in Game1.debrisWeather) - weatherDebris.draw(Game1.spriteBatch); - } - } + this.drawWeather(gameTime, target_screen); if (Game1.farmEvent != null) Game1.farmEvent.draw(Game1.spriteBatch); if ((double)Game1.currentLocation.LightLevel > 0.0 && Game1.timeOfDay < 2000) @@ -1224,22 +1204,6 @@ namespace StardewModdingAPI.Framework Game1.currentLocation.drawAboveAlwaysFrontLayer(Game1.spriteBatch); if (Game1.player.CurrentTool != null && Game1.player.CurrentTool is FishingRod && ((Game1.player.CurrentTool as FishingRod).isTimingCast || (double)(Game1.player.CurrentTool as FishingRod).castingChosenCountdown > 0.0 || ((Game1.player.CurrentTool as FishingRod).fishCaught || (Game1.player.CurrentTool as FishingRod).showingTreasure))) Game1.player.CurrentTool.draw(Game1.spriteBatch); - if (Game1.isRaining && Game1.currentLocation.IsOutdoors && (!Game1.currentLocation.Name.Equals("Desert") && !(Game1.currentLocation is Summit))) - { - if (this.takingMapScreenshot) - { - for (int index = 0; index < Game1.rainDrops.Length; ++index) - { - Vector2 position = new Vector2((float)Game1.random.Next(Game1.viewport.Width - 64), (float)Game1.random.Next(Game1.viewport.Height - 64)); - Game1.spriteBatch.Draw(Game1.rainTexture, position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Microsoft.Xna.Framework.Color.White); - } - } - else if (!Game1.eventUp || Game1.currentLocation.isTileOnMap(new Vector2((float)(Game1.viewport.X / 64), (float)(Game1.viewport.Y / 64)))) - { - for (int index = 0; index < Game1.rainDrops.Length; ++index) - Game1.spriteBatch.Draw(Game1.rainTexture, Game1.rainDrops[index].position, new Microsoft.Xna.Framework.Rectangle?(Game1.getSourceRectForStandardTileSheet(Game1.rainTexture, Game1.rainDrops[index].frame, -1, -1)), Microsoft.Xna.Framework.Color.White); - } - } Game1.spriteBatch.End(); Game1.spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); if (Game1.eventUp && Game1.currentLocation.currentEvent != null) -- cgit From 41a809a2e063eec9c39868768512084e0a14256f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 2 Oct 2019 17:37:14 -0400 Subject: fix render events not raised during minigames --- docs/release-notes.md | 1 + src/SMAPI/Framework/SGame.cs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 5f643f07..3771ec19 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -123,6 +123,7 @@ For modders: * Fixed issue where, when a mod's `IAssetEditor` uses `asset.ReplaceWith` on a texture asset while playing in non-English, any changes from that point won't affect subsequent cached asset loads. * Fixed asset propagation for NPC portraits resetting any unique portraits (e.g. Maru's hospital portrait) to the default. * Fixed changes to `Data\NPCDispositions` not always propagated correctly to existing NPCs. + * Fixed `Rendering`/`Rendered` events not raised during minigames. * Fixed `LoadStageChanged` event not raising correct flags in some cases when creating a new save. * Fixed `GetApi` without an interface not checking if all mods are loaded. diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index cabbbc3a..aa84295c 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -908,6 +908,14 @@ namespace StardewModdingAPI.Framework } else if (Game1.currentMinigame != null) { + int batchEnds = 0; + + if (events.Rendering.HasListeners()) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + events.Rendering.RaiseEmpty(); + Game1.spriteBatch.End(); + } Game1.currentMinigame.draw(Game1.spriteBatch); if (Game1.globalFade && !Game1.menuUp && (!Game1.nameSelectUp || Game1.messagePause)) { @@ -917,11 +925,21 @@ namespace StardewModdingAPI.Framework } this.drawOverlays(Game1.spriteBatch); if (target_screen == null) + { + if (++batchEnds == 1 && events.Rendered.HasListeners()) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + events.Rendered.RaiseEmpty(); + Game1.spriteBatch.End(); + } return; + } this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); this.GraphicsDevice.Clear(Game1.bgColor); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone); Game1.spriteBatch.Draw((Texture2D)target_screen, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(target_screen.Bounds), Microsoft.Xna.Framework.Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); + if (++batchEnds == 1) + events.Rendered.RaiseEmpty(); Game1.spriteBatch.End(); } else if (Game1.showingEndOfNightStuff) -- cgit From 31db556d02b27aa246ea3a5ae0c94dcdd7a5f7f0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 2 Oct 2019 21:56:59 -0400 Subject: update for more draw changes (#638) --- src/SMAPI/Framework/SGame.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index aa84295c..47261862 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -762,12 +762,14 @@ namespace StardewModdingAPI.Framework /// The method called to draw everything to the screen. /// A snapshot of the game timing state. - protected override void Draw(GameTime gameTime) + /// The render target, if any. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "copied from game code as-is")] + protected override void _draw(GameTime gameTime, RenderTarget2D target_screen) { Context.IsInDrawLoop = true; try { - this.DrawImpl(gameTime); + this.DrawImpl(gameTime, target_screen); this.DrawCrashTimer.Reset(); } catch (Exception ex) @@ -801,8 +803,10 @@ namespace StardewModdingAPI.Framework /// Replicate the game's draw logic with some changes for SMAPI. /// A snapshot of the game timing state. + /// The render target, if any. /// This implementation is identical to , except for try..catch around menu draw code, private field references replaced by wrappers, and added events. [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator", Justification = "copied from game code as-is")] + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "LocalVariableHidesMember", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "PossibleLossOfFraction", Justification = "copied from game code as-is")] [SuppressMessage("ReSharper", "RedundantArgumentDefaultValue", Justification = "copied from game code as-is")] @@ -811,16 +815,10 @@ namespace StardewModdingAPI.Framework [SuppressMessage("ReSharper", "RedundantTypeArgumentsOfMethod", Justification = "copied from game code as-is")] [SuppressMessage("SMAPI.CommonErrors", "AvoidNetField", Justification = "copied from game code as-is")] [SuppressMessage("SMAPI.CommonErrors", "AvoidImplicitNetFieldCast", Justification = "copied from game code as-is")] - private void DrawImpl(GameTime gameTime) + private void DrawImpl(GameTime gameTime, RenderTarget2D target_screen) { var events = this.Events; - // from Game1.Draw - RenderTarget2D target_screen = (RenderTarget2D)null; - if ((double)Game1.options.zoomLevel != 1.0) - target_screen = this.screen; - - // from Game1._draw if (Game1._newDayTask != null) { this.GraphicsDevice.Clear(Game1.bgColor); @@ -1039,7 +1037,7 @@ namespace StardewModdingAPI.Framework continue; } if (Utility.isOnScreen((Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position), (int)((double)(float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) * 64.0 * 4.0))) - Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Microsoft.Xna.Framework.Color) ((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); + Game1.spriteBatch.Draw(Game1.currentLightSources.ElementAt(index).lightTexture, Game1.GlobalToLocal(Game1.viewport, (Vector2)((NetFieldBase)Game1.currentLightSources.ElementAt(index).position)) / (float)(Game1.options.lightingQuality / 2), new Microsoft.Xna.Framework.Rectangle?(Game1.currentLightSources.ElementAt(index).lightTexture.Bounds), (Microsoft.Xna.Framework.Color)((NetFieldBase)Game1.currentLightSources.ElementAt(index).color), 0.0f, new Vector2((float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.X, (float)Game1.currentLightSources.ElementAt(index).lightTexture.Bounds.Center.Y), (float)((NetFieldBase)Game1.currentLightSources.ElementAt(index).radius) / (float)(Game1.options.lightingQuality / 2), SpriteEffects.None, 0.9f); } } Game1.spriteBatch.End(); -- cgit From f154c5774d6e6197d63ca284606ce965a920d212 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 18 Nov 2019 21:07:52 -0500 Subject: minor updates (#638) --- src/SMAPI/Framework/SCore.cs | 8 -------- src/SMAPI/Metadata/CoreAssetPropagator.cs | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 77b17c8a..afb82679 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -96,12 +96,6 @@ namespace StardewModdingAPI.Framework new Regex(@"^DebugOutput:\s+(?:added CLOUD|added cricket|dismount tile|Ping|playerPos)", RegexOptions.Compiled | RegexOptions.CultureInvariant) }; - /// Regex patterns which match console error messages to suppress from the console and log. - private readonly Regex[] SuppressConsoleErrorPatterns = - { - new Regex(@"^Error loading schedule data for (?:Bouncer|Dwarf|Gunther|Henchman|Krobus|Marlon|Mister Qi|Sandy|Wizard): .+ ---> System\.IO\.FileNotFoundException", RegexOptions.Compiled | RegexOptions.CultureInvariant) - }; - /// Regex patterns which match console messages to show a more friendly error for. private readonly Tuple[] ReplaceConsolePatterns = { @@ -1321,8 +1315,6 @@ namespace StardewModdingAPI.Framework // ignore suppressed message if (level != LogLevel.Error && this.SuppressConsolePatterns.Any(p => p.IsMatch(message))) return; - if (level == LogLevel.Error && this.SuppressConsoleErrorPatterns.Any(p => p.IsMatch(message))) - return; // show friendly error if applicable foreach (var entry in this.ReplaceConsolePatterns) diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index a6bfab5c..9bb9a857 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -735,7 +735,7 @@ namespace StardewModdingAPI.Metadata { Lazy texture = new Lazy(() => content.Load(key)); foreach (Tree tree in trees) - this.Reflection.GetField>(tree, "texture").SetValue(texture); + tree.texture = texture; return true; } -- cgit From 5c1516aaab3a542a73e625e723d4e4425809946c Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 18 Nov 2019 21:08:48 -0500 Subject: optimise map tilesheet fixing slightly --- src/SMAPI/Framework/ContentManagers/ModContentManager.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index b88bd71e..90b86179 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -240,7 +240,13 @@ namespace StardewModdingAPI.Framework.ContentManagers Color[] data = new Color[texture.Width * texture.Height]; texture.GetData(data); for (int i = 0; i < data.Length; i++) + { + if (data[i].A == 0) + continue; // no need to change fully transparent pixels + data[i] = Color.FromNonPremultiplied(data[i].ToVector4()); + } + texture.SetData(data); return texture; } -- cgit From f0f348bd5f5f4aa27030febe8a057eab9c50db7d Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 24 Nov 2019 12:13:34 -0500 Subject: update packages --- docs/release-notes.md | 2 +- .../SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 2 +- src/SMAPI.Tests/SMAPI.Tests.csproj | 4 ++-- src/SMAPI.Toolkit/SMAPI.Toolkit.csproj | 4 ++-- src/SMAPI.Web/SMAPI.Web.csproj | 16 ++++++++-------- src/SMAPI/SMAPI.csproj | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/SMAPI') diff --git a/docs/release-notes.md b/docs/release-notes.md index 3771ec19..f11d285c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -115,7 +115,7 @@ For modders: * Trace logs when loading mods are now more clear. * Clarified update-check errors for mods with multiple update keys. * `SemanticVersion` no longer omits `.0` patch numbers when formatting versions, for better [semver](https://semver.org/) conformity (e.g. `3.0` is now formatted as `3.0.0`). - * Updated dependencies (including Json.NET 11.0.2 → 12.0.2 and Mono.Cecil 0.10.1 → 0.11). + * Updated dependencies (including Json.NET 11.0.2 → 12.0.3 and Mono.Cecil 0.10.1 → 0.11.1). * Fixes: * Fixed custom maps loaded from `.xnb` files not having their tilesheet paths automatically adjusted. * Fixed custom maps loaded from the mod folder with tilesheets in a subfolder not working crossplatform. All tilesheet paths are now normalized for the OS automatically. diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index e7c3e3dc..7e3ce7d4 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/SMAPI.Tests/SMAPI.Tests.csproj b/src/SMAPI.Tests/SMAPI.Tests.csproj index 84a05aee..639c22a4 100644 --- a/src/SMAPI.Tests/SMAPI.Tests.csproj +++ b/src/SMAPI.Tests/SMAPI.Tests.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj index a932c41b..3bb7e313 100644 --- a/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj +++ b/src/SMAPI.Toolkit/SMAPI.Toolkit.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/src/SMAPI.Web/SMAPI.Web.csproj b/src/SMAPI.Web/SMAPI.Web.csproj index c6ee7594..8a7ca741 100644 --- a/src/SMAPI.Web/SMAPI.Web.csproj +++ b/src/SMAPI.Web/SMAPI.Web.csproj @@ -12,19 +12,19 @@ - - - - - + + + + + - - + + - + diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 62002a40..4952116f 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -18,8 +18,8 @@ - - + + -- cgit From 7048f3756312f344dc06a8b98fdce2546d0681f2 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 21 Apr 2019 17:54:03 -0400 Subject: add asset propagation for new assets in SDV 1.4 (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 53 ++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 9bb9a857..4eab12c9 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -8,6 +8,7 @@ using StardewValley; using StardewValley.BellsAndWhistles; using StardewValley.Buildings; using StardewValley.Characters; +using StardewValley.GameData.Movies; using StardewValley.Locations; using StardewValley.Menus; using StardewValley.Objects; @@ -167,10 +168,6 @@ namespace StardewModdingAPI.Metadata /**** ** Animals ****/ - case "animals\\cat": - return this.ReloadPetOrHorseSprites(content, key); - case "animals\\dog": - return this.ReloadPetOrHorseSprites(content, key); case "animals\\horse": return this.ReloadPetOrHorseSprites(content, key); @@ -189,12 +186,14 @@ namespace StardewModdingAPI.Metadata return true; case "characters\\farmer\\farmer_base": // Farmer + case "characters\\farmer\\farmer_base_bald": if (Game1.player == null || !Game1.player.IsMale) return false; Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); return true; case "characters\\farmer\\farmer_girl_base": // Farmer + case "characters\\farmer\\farmer_girl_bald": if (Game1.player == null || Game1.player.IsMale) return false; Game1.player.FarmerRenderer = new FarmerRenderer(key, Game1.player); @@ -208,6 +207,10 @@ namespace StardewModdingAPI.Metadata FarmerRenderer.hatsTexture = content.Load(key); return true; + case "characters\\farmer\\pants": // Game1.LoadContent + FarmerRenderer.pantsTexture = content.Load(key); + return true; + case "characters\\farmer\\shirts": // Game1.LoadContent FarmerRenderer.shirtsTexture = content.Load(key); return true; @@ -223,6 +226,16 @@ namespace StardewModdingAPI.Metadata Game1.bigCraftablesInformation = content.Load>(key); return true; + case "data\\clothinginformation": // Game1.LoadContent + Game1.clothingInformation = content.Load>(key); + return true; + + case "data\\concessiontastes": // MovieTheater.GetConcessionTasteForCharacter + this.Reflection + .GetField>(typeof(MovieTheater), "_concessionTastes") + .SetValue(content.Load>(key)); + return true; + case "data\\cookingrecipes": // CraftingRecipe.InitShared CraftingRecipe.cookingRecipes = content.Load>(key); return true; @@ -234,6 +247,18 @@ namespace StardewModdingAPI.Metadata case "data\\farmanimals": // FarmAnimal constructor return this.ReloadFarmAnimalData(); + case "data\\moviereactions": // MovieTheater.GetMovieReactions + this.Reflection + .GetField>(typeof(MovieTheater), "_genericReactions") + .SetValue(content.Load>(key)); + return true; + + case "data\\movies": // MovieTheater.GetMovieData + this.Reflection + .GetField>(typeof(MovieTheater), "_movieData") + .SetValue(content.Load>(key)); + return true; + case "data\\npcdispositions": // NPC constructor return this.ReloadNpcDispositions(content, key); @@ -241,6 +266,10 @@ namespace StardewModdingAPI.Metadata Game1.NPCGiftTastes = content.Load>(key); return true; + case "data\\objectcontexttags": // Game1.LoadContent + Game1.objectContextTags = content.Load>(key); + return true; + case "data\\objectinformation": // Game1.LoadContent Game1.objectInformation = content.Load>(key); return true; @@ -290,6 +319,14 @@ namespace StardewModdingAPI.Metadata /**** ** Content\LooseSprites ****/ + case "loosesprites\\birds": // Game1.LoadContent + Game1.birdsSpriteSheet = content.Load(key); + return true; + + case "loosesprites\\concessions": // Game1.LoadContent + Game1.concessionsSpriteSheet = content.Load(key); + return true; + case "loosesprites\\controllermaps": // Game1.LoadContent Game1.controllerMaps = content.Load(key); return true; @@ -373,6 +410,10 @@ namespace StardewModdingAPI.Metadata Game1.menuTexture = content.Load(key); return true; + case "maps\\menutilesuncolored": // Game1.LoadContent + Game1.uncoloredMenuTexture = content.Load(key); + return true; + case "maps\\springobjects": // Game1.LoadContent Game1.objectSpriteSheet = content.Load(key); return true; @@ -474,6 +515,10 @@ namespace StardewModdingAPI.Metadata } // dynamic textures + if (this.KeyStartsWith(key, "animals\\cat")) + return this.ReloadPetOrHorseSprites(content, key); + if (this.KeyStartsWith(key, "animals\\dog")) + return this.ReloadPetOrHorseSprites(content, key); if (this.IsInFolder(key, "Animals")) return this.ReloadFarmAnimalSprites(content, key); -- cgit From eaf31f992f7bd415f126816de9f1e4f3f3100b73 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 18 Aug 2019 00:43:57 -0400 Subject: update movie data propagation (#638) --- src/SMAPI/Metadata/CoreAssetPropagator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/SMAPI') diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 4eab12c9..1c0a04f0 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -255,8 +255,8 @@ namespace StardewModdingAPI.Metadata case "data\\movies": // MovieTheater.GetMovieData this.Reflection - .GetField>(typeof(MovieTheater), "_movieData") - .SetValue(content.Load>(key)); + .GetField>(typeof(MovieTheater), "_movieData") + .SetValue(content.Load>(key)); return true; case "data\\npcdispositions": // NPC constructor -- cgit