From 441ded8c9a9e3dea39cb180df429d3fcc5f3cc96 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 9 Dec 2018 18:52:21 -0500 Subject: fix error when a mod makes invalid changes to an NPC schedule --- docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 9047ae88..63343d0a 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,4 +1,8 @@ # Release notes +## Upcoming release +* For players: + * Fixed error when a mod makes invalid changes to an NPC schedule. + ## 2.9.1 * For players: * Fixed crash in SMAPI 2.9 when constructing certain buildings. -- cgit From 3fef9bb2a5cc39fc6ba15199b0889fae5533c5f0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 9 Dec 2018 19:35:38 -0500 Subject: fix 'begin must be called' sprite batch errors when using Display.RenderedWorld event --- docs/release-notes.md | 1 + src/SMAPI/Framework/SGame.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 63343d0a..6033b141 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Upcoming release * For players: * Fixed error when a mod makes invalid changes to an NPC schedule. + * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. ## 2.9.1 * For players: diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 7b3335b7..4d790d9f 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -1422,8 +1422,8 @@ namespace StardewModdingAPI.Framework } Game1.spriteBatch.End(); } - this.Events.RenderedWorld.RaiseEmpty(); Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); + this.Events.RenderedWorld.RaiseEmpty(); if (Game1.drawGrid) { int num1 = -Game1.viewport.X % 64; -- cgit From cd277e915f85260c8af665b5aeb44368badf06e8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 13 Dec 2018 00:34:28 -0500 Subject: fix NPCDisposition asset propagation breaking NPC data --- docs/release-notes.md | 1 + src/SMAPI/Metadata/CoreAssetPropagator.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 6033b141..6c10b4ac 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Upcoming release * For players: * Fixed error when a mod makes invalid changes to an NPC schedule. + * Fixed invalid NPC data propagated when a mod changes NPC dispositions. * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. ## 2.9.1 diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 4667be7e..a44ab7d1 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -504,7 +504,7 @@ namespace StardewModdingAPI.Metadata if (!character.isVillager() || !dispositions.ContainsKey(character.Name)) continue; - NPC clone = new NPC(null, Vector2.Zero, 0, character.Name); + 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; -- cgit From e447ce225f46f60131519a1ff77dfddf520696bb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 13 Dec 2018 01:16:38 -0500 Subject: add content pack API --- docs/release-notes.md | 3 + src/SMAPI/Framework/ModHelpers/CommandHelper.cs | 2 +- .../Framework/ModHelpers/ContentPackHelper.cs | 82 ++++++++++++++++++++++ src/SMAPI/Framework/ModHelpers/ModHelper.cs | 59 +++------------- src/SMAPI/Framework/SCore.cs | 5 +- src/SMAPI/ICommandHelper.cs | 2 +- src/SMAPI/IContentPackHelper.cs | 27 +++++++ src/SMAPI/IModHelper.cs | 22 ++---- src/SMAPI/StardewModdingAPI.csproj | 2 + 9 files changed, 136 insertions(+), 68 deletions(-) create mode 100644 src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs create mode 100644 src/SMAPI/IContentPackHelper.cs (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 6c10b4ac..de0bdf71 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,9 @@ * Fixed invalid NPC data propagated when a mod changes NPC dispositions. * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. +* For modders: + * Added dedicated content pack API. + ## 2.9.1 * For players: * Fixed crash in SMAPI 2.9 when constructing certain buildings. diff --git a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs index 5a3304f3..a4fd21c1 100644 --- a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs @@ -6,7 +6,7 @@ namespace StardewModdingAPI.Framework.ModHelpers internal class CommandHelper : BaseHelper, ICommandHelper { /********* - ** Accessors + ** Properties *********/ /// The mod using this instance. private readonly IModMetadata Mod; diff --git a/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs b/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs new file mode 100644 index 00000000..c4b86cda --- /dev/null +++ b/src/SMAPI/Framework/ModHelpers/ContentPackHelper.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.IO; +using StardewModdingAPI.Toolkit.Serialisation.Models; + +namespace StardewModdingAPI.Framework.ModHelpers +{ + /// Provides an API for managing content packs. + internal class ContentPackHelper : BaseHelper, IContentPackHelper + { + /********* + ** Properties + *********/ + /// The content packs loaded for this mod. + private readonly Lazy ContentPacks; + + /// Create a temporary content pack. + private readonly Func CreateContentPack; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The unique ID of the relevant mod. + /// The content packs loaded for this mod. + /// Create a temporary content pack. + public ContentPackHelper(string modID, Lazy contentPacks, Func createContentPack) + : base(modID) + { + this.ContentPacks = contentPacks; + this.CreateContentPack = createContentPack; + } + + /// Get all content packs loaded for this mod. + public IEnumerable GetOwned() + { + return this.ContentPacks.Value; + } + + /// Create a temporary content pack to read files from a directory. 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) + { + string id = Guid.NewGuid().ToString("N"); + return this.CreateFake(directoryPath, id, id, id, id, new SemanticVersion(1, 0, 0)); + } + + /// Create a temporary content pack to read files from a directory. 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. + /// The content pack's unique ID. + /// The content pack name. + /// The content pack description. + /// The content pack author's name. + /// The content pack version. + public IContentPack CreateFake(string directoryPath, string id, string name, string description, string author, ISemanticVersion version) + { + // validate + if (string.IsNullOrWhiteSpace(directoryPath)) + throw new ArgumentNullException(nameof(directoryPath)); + if (string.IsNullOrWhiteSpace(id)) + throw new ArgumentNullException(nameof(id)); + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentNullException(nameof(name)); + if (!Directory.Exists(directoryPath)) + throw new ArgumentException($"Can't create content pack for directory path '{directoryPath}' because no such directory exists."); + + // create manifest + IManifest manifest = new Manifest( + uniqueID: id, + name: name, + author: author, + description: description, + version: version, + contentPackFor: this.ModID + ); + + // create content pack + return this.CreateContentPack(directoryPath, manifest); + } + } +} diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs index 070d9c65..87d405e9 100644 --- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs +++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs @@ -15,12 +15,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /********* ** Properties *********/ - /// The content packs loaded for this mod. - private readonly Lazy ContentPacks; - - /// Create a transitional content pack. - private readonly Func CreateContentPack; - #if !SMAPI_3_0_STRICT /// Manages deprecation warnings. private readonly DeprecationManager DeprecationManager; @@ -44,6 +38,9 @@ namespace StardewModdingAPI.Framework.ModHelpers /// An API for loading content assets. public IContentHelper Content { get; } + /// An API for managing content packs. + public IContentPackHelper ContentPacks { get; } + /// An API for reading and writing persistent mod data. public IDataHelper Data { get; } @@ -76,18 +73,17 @@ namespace StardewModdingAPI.Framework.ModHelpers /// Manages the game's input state. /// Manages access to events raised by SMAPI. /// An API for loading content assets. + /// An API for managing content packs. /// An API for managing console commands. /// An API for reading and writing persistent mod data. /// an API for fetching metadata about loaded mods. /// An API for accessing private game code. /// Provides multiplayer utilities. /// An API for reading translations stored in the mod's i18n folder. - /// The content packs loaded for this mod. - /// Create a transitional content pack. /// Manages deprecation warnings. /// 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, ICommandHelper commandHelper, IDataHelper dataHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, Func contentPacks, Func createContentPack, DeprecationManager deprecationManager) + 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, DeprecationManager deprecationManager) : base(modID) { // validate directory @@ -99,6 +95,7 @@ namespace StardewModdingAPI.Framework.ModHelpers // initialise this.DirectoryPath = modDirectory; this.Content = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper)); + this.ContentPacks = contentPackHelper ?? throw new ArgumentNullException(nameof(contentPackHelper)); this.Data = dataHelper ?? throw new ArgumentNullException(nameof(dataHelper)); this.Input = new InputHelper(modID, inputState); this.ModRegistry = modRegistry ?? throw new ArgumentNullException(nameof(modRegistry)); @@ -106,8 +103,6 @@ namespace StardewModdingAPI.Framework.ModHelpers this.Reflection = reflectionHelper ?? throw new ArgumentNullException(nameof(reflectionHelper)); this.Multiplayer = multiplayer ?? throw new ArgumentNullException(nameof(multiplayer)); this.Translation = translationHelper ?? throw new ArgumentNullException(nameof(translationHelper)); - this.ContentPacks = new Lazy(contentPacks); - this.CreateContentPack = createContentPack; this.Events = events; #if !SMAPI_3_0_STRICT this.JsonHelper = jsonHelper ?? throw new ArgumentNullException(nameof(jsonHelper)); @@ -171,39 +166,6 @@ namespace StardewModdingAPI.Framework.ModHelpers /**** ** Content packs ****/ - /// Create a temporary content pack to read files from a directory. 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. - /// The content pack's unique ID. - /// The content pack name. - /// The content pack description. - /// The content pack author's name. - /// The content pack version. - public IContentPack CreateTemporaryContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version) - { - // validate - if (string.IsNullOrWhiteSpace(directoryPath)) - throw new ArgumentNullException(nameof(directoryPath)); - if (string.IsNullOrWhiteSpace(id)) - throw new ArgumentNullException(nameof(id)); - if (string.IsNullOrWhiteSpace(name)) - throw new ArgumentNullException(nameof(name)); - if (!Directory.Exists(directoryPath)) - throw new ArgumentException($"Can't create content pack for directory path '{directoryPath}' because no such directory exists."); - - // create manifest - IManifest manifest = new Manifest( - uniqueID: id, - name: name, - author: author, - description: description, - version: version, - contentPackFor: this.ModID - ); - - // create content pack - return this.CreateContentPack(directoryPath, manifest); - } - #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. @@ -212,19 +174,20 @@ namespace StardewModdingAPI.Framework.ModHelpers /// The content pack description. /// The content pack author's name. /// The content pack version. - [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.CreateTemporaryContentPack) + " instead")] + [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ContentPacks) + "." + nameof(IContentPackHelper.CreateFake) + " instead")] public IContentPack CreateTransitionalContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version) { this.DeprecationManager.Warn($"{nameof(IModHelper)}.{nameof(IModHelper.CreateTransitionalContentPack)}", "2.5", DeprecationLevel.Notice); - return this.CreateTemporaryContentPack(directoryPath, id, name, description, author, version); + return this.ContentPacks.CreateFake(directoryPath, id, name, description, author, version); } -#endif /// 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.Value; + return this.ContentPacks.GetOwned(); } +#endif /**** ** Disposal diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 800b9c09..76b091d0 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -1014,20 +1014,21 @@ namespace StardewModdingAPI.Framework 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); + IContentPackHelper contentPackHelper = new ContentPackHelper(manifest.UniqueID, new Lazy(GetContentPacks), CreateFakeContentPack); IDataHelper dataHelper = new DataHelper(manifest.UniqueID, mod.DirectoryPath, jsonHelper); IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, mod.DisplayName, this.Reflection, this.DeprecationManager); 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 CreateTransitionalContentPack(string packDirPath, IManifest packManifest) + 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); } - modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.Toolkit.JsonHelper, this.GameInstance.Input, events, contentHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper, GetContentPacks, CreateTransitionalContentPack, this.DeprecationManager); + modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, this.Toolkit.JsonHelper, this.GameInstance.Input, events, contentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper, this.DeprecationManager); } // init mod diff --git a/src/SMAPI/ICommandHelper.cs b/src/SMAPI/ICommandHelper.cs index fb562e32..196e1051 100644 --- a/src/SMAPI/ICommandHelper.cs +++ b/src/SMAPI/ICommandHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace StardewModdingAPI { diff --git a/src/SMAPI/IContentPackHelper.cs b/src/SMAPI/IContentPackHelper.cs new file mode 100644 index 00000000..0c734432 --- /dev/null +++ b/src/SMAPI/IContentPackHelper.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +namespace StardewModdingAPI +{ + /// Provides an API for managing content packs. + public interface IContentPackHelper : IModLinked + { + /********* + ** Public methods + *********/ + /// Get all content packs loaded for this mod. + IEnumerable GetOwned(); + + /// Create a temporary content pack to read files from a directory. 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); + + /// Create a temporary content pack to read files from a directory. 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. + /// The content pack's unique ID. + /// The content pack name. + /// The content pack description. + /// The content pack author's name. + /// The content pack version. + IContentPack CreateFake(string directoryPath, string id, string name, string description, string author, ISemanticVersion version); + } +} diff --git a/src/SMAPI/IModHelper.cs b/src/SMAPI/IModHelper.cs index fbe3d51f..21bc5727 100644 --- a/src/SMAPI/IModHelper.cs +++ b/src/SMAPI/IModHelper.cs @@ -22,6 +22,9 @@ namespace StardewModdingAPI /// An API for loading content assets. IContentHelper Content { get; } + /// An API for managing content packs. + IContentPackHelper ContentPacks { get; } + /// An API for reading and writing persistent mod data. IDataHelper Data { get; } @@ -73,21 +76,7 @@ namespace StardewModdingAPI /// The model to save. [Obsolete("Use " + nameof(IModHelper.Data) + "." + nameof(IDataHelper.WriteJsonFile) + " instead")] void WriteJsonFile(string path, TModel model) where TModel : class; -#endif - - /**** - ** Content packs - ****/ - /// Create a temporary content pack to read files from a directory. 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. - /// The content pack's unique ID. - /// The content pack name. - /// The content pack description. - /// The content pack author's name. - /// The content pack version. - IContentPack CreateTemporaryContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version); -#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. @@ -95,11 +84,12 @@ namespace StardewModdingAPI /// The content pack description. /// The content pack author's name. /// The content pack version. - [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.CreateTemporaryContentPack) + " instead")] + [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ContentPacks) + "." + nameof(IContentPackHelper.CreateFake) + " instead")] IContentPack CreateTransitionalContentPack(string directoryPath, string id, string name, string description, string author, ISemanticVersion version); -#endif /// 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/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 49a88f37..2c769f41 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -174,6 +174,7 @@ + @@ -207,6 +208,7 @@ + -- cgit From fd47e992dbdbf4298fd9130b8ef9bfcf52fcab19 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 13 Dec 2018 02:01:23 -0500 Subject: deprecate assetData.AsDictionary().Set --- docs/release-notes.md | 2 ++ src/SMAPI/Framework/Content/AssetDataForDictionary.cs | 8 ++++++++ src/SMAPI/IAssetDataForDictionary.cs | 8 +++++++- 3 files changed, 17 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index de0bdf71..e51ff0a5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -7,6 +7,8 @@ * For modders: * Added dedicated content pack API. + * **Deprecations:** + * The `assetData.AsDictionary().Set` methods are deprecated and will be removed in SMAPI 3.0. Mods should access the `Data` property directly instead. ## 2.9.1 * For players: diff --git a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs index 7b80875f..9bd70711 100644 --- a/src/SMAPI/Framework/Content/AssetDataForDictionary.cs +++ b/src/SMAPI/Framework/Content/AssetDataForDictionary.cs @@ -19,28 +19,36 @@ namespace StardewModdingAPI.Framework.Content 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.Notice); 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.Notice); 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.Notice); foreach (var pair in this.Data.ToArray()) this.Data[pair.Key] = replacer(pair.Key, pair.Value); } +#endif } } diff --git a/src/SMAPI/IAssetDataForDictionary.cs b/src/SMAPI/IAssetDataForDictionary.cs index 53c24346..911599d9 100644 --- a/src/SMAPI/IAssetDataForDictionary.cs +++ b/src/SMAPI/IAssetDataForDictionary.cs @@ -1,26 +1,32 @@ -using System; +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 } } -- cgit From 8eee91c67db0f09e9c604c7b4a2809e5bc937258 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 14 Dec 2018 00:23:48 -0500 Subject: fix game launch error logged as 'SMAPI' --- docs/release-notes.md | 1 + src/SMAPI/Framework/SCore.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index e51ff0a5..9df18098 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ * Fixed error when a mod makes invalid changes to an NPC schedule. * Fixed invalid NPC data propagated when a mod changes NPC dispositions. * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. + * Fixed game launch crash logged as `SMAPI` instead of `game`. * For modders: * Added dedicated content pack API. diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 3749bab4..e43d3f8b 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -315,7 +315,7 @@ namespace StardewModdingAPI.Framework } catch (Exception ex) { - this.Monitor.Log($"The game failed unexpectedly: {ex.GetLogSummary()}", LogLevel.Error); + this.MonitorForGame.Log($"The game failed to launch: {ex.GetLogSummary()}", LogLevel.Error); this.PressAnyKeyToExit(); } finally -- cgit From 0d26285da12156c6304c1ff4458bd0b62e6e8dca Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 14 Dec 2018 00:42:00 -0500 Subject: add friendly error when the game can't find its Content\XACT folder --- docs/release-notes.md | 1 + src/SMAPI.Web/Startup.cs | 1 + src/SMAPI/Framework/SCore.cs | 6 ++++++ 3 files changed, 8 insertions(+) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 9df18098..c3b11d7f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,7 @@ # Release notes ## Upcoming release * For players: + * Fixed cryptic error message when the game isn't installed correctly. * Fixed error when a mod makes invalid changes to an NPC schedule. * Fixed invalid NPC data propagated when a mod changes NPC dispositions. * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index 0bd71d26..4e3aaed3 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -165,6 +165,7 @@ namespace StardewModdingAPI.Web redirects.Add(new RedirectToUrlRule(@"^/3\.0\.?$", "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0")); redirects.Add(new RedirectToUrlRule(@"^/docs\.?$", "https://stardewvalleywiki.com/Modding:Index")); redirects.Add(new RedirectToUrlRule(@"^/install\.?$", "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI")); + redirects.Add(new RedirectToUrlRule(@"^/troubleshoot(.*)$", "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1")); // redirect legacy canimod.com URLs var wikiRedirects = new Dictionary diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index e43d3f8b..3bc0aca4 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -313,6 +313,12 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"Technical details: {ex.GetLogSummary()}", LogLevel.Trace); this.PressAnyKeyToExit(); } + catch (FileNotFoundException ex) when (ex.Message == "Could not find file 'C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Stardew Valley\\Content\\XACT\\FarmerSounds.xgs'.") // path in error is hardcoded regardless of install path + { + this.Monitor.Log("The game can't find its Content\\XACT\\FarmerSounds.xgs file. You can usually fix this by resetting your content files (see https://smapi.io/troubleshoot#reset-content ), or by uninstalling and reinstalling the game.", LogLevel.Error); + this.Monitor.Log($"Technical details: {ex.GetLogSummary()}", LogLevel.Trace); + this.PressAnyKeyToExit(); + } catch (Exception ex) { this.MonitorForGame.Log($"The game failed to launch: {ex.GetLogSummary()}", LogLevel.Error); -- cgit From 567c216161f00767b5dcdb0adf40a3bee91d18d0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 14 Dec 2018 18:59:49 -0500 Subject: fix unix launcher included in Windows installer --- build/prepare-install-package.targets | 4 ++-- docs/release-notes.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index 3a870bd2..cd758e96 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -33,7 +33,6 @@ - @@ -50,9 +49,10 @@ - + + diff --git a/docs/release-notes.md b/docs/release-notes.md index c3b11d7f..0e426bfd 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -6,6 +6,7 @@ * Fixed invalid NPC data propagated when a mod changes NPC dispositions. * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. * Fixed game launch crash logged as `SMAPI` instead of `game`. + * Fixed Windows installer adding unneeded Unix launcher to game folder. * For modders: * Added dedicated content pack API. -- cgit From 5f620e14fa331b0721bd4044011363477dc79ef5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Dec 2018 00:18:51 -0500 Subject: add SMAPI 3.0 readiness to API data (#606) --- docs/release-notes.md | 3 ++ src/SMAPI.Web/ViewModels/ModModel.cs | 8 ++++++ src/SMAPI.Web/Views/Mods/Index.cshtml | 14 ++++++++- src/SMAPI.Web/wwwroot/Content/js/mods.js | 33 +++++++++++++++++++++- .../Clients/WebApi/ModExtendedMetadataModel.cs | 12 ++++++++ .../Framework/Clients/Wiki/WikiClient.cs | 21 +++++++++----- .../Framework/Clients/Wiki/WikiModEntry.cs | 6 ++++ .../Framework/Clients/Wiki/WikiSmapi3Status.cs | 18 ++++++++++++ 8 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiSmapi3Status.cs (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 0e426bfd..fa7f4109 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -13,6 +13,9 @@ * **Deprecations:** * The `assetData.AsDictionary().Set` methods are deprecated and will be removed in SMAPI 3.0. Mods should access the `Data` property directly instead. +* FOR SMAPI developers: + * Added SMAPI 3.0 readiness to mod API data. + ## 2.9.1 * For players: * Fixed crash in SMAPI 2.9 when constructing certain buildings. diff --git a/src/SMAPI.Web/ViewModels/ModModel.cs b/src/SMAPI.Web/ViewModels/ModModel.cs index 5c1840fc..f1a52f98 100644 --- a/src/SMAPI.Web/ViewModels/ModModel.cs +++ b/src/SMAPI.Web/ViewModels/ModModel.cs @@ -31,6 +31,12 @@ namespace StardewModdingAPI.Web.ViewModels /// The compatibility status for the beta version of the game. public ModCompatibilityModel BetaCompatibility { get; set; } + /// Whether the mod is ready for the upcoming SMAPI 3.0. + public string Smapi3Status { get; set; } + + /// A URL related to the . + public string Smapi3Url { get; set; } + /// Links to the available mod pages. public ModLinkModel[] ModPages { get; set; } @@ -59,6 +65,8 @@ namespace StardewModdingAPI.Web.ViewModels this.SourceUrl = this.GetSourceUrl(entry); this.Compatibility = new ModCompatibilityModel(entry.Compatibility); this.BetaCompatibility = entry.BetaCompatibility != null ? new ModCompatibilityModel(entry.BetaCompatibility) : null; + this.Smapi3Status = entry.Smapi3Status.ToString().ToLower(); + this.Smapi3Url = entry.Smapi3Url; this.ModPages = this.GetModPageUrls(entry).ToArray(); this.Warnings = entry.Warnings; this.Slug = entry.Anchor; diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml index a49a24d9..67034322 100644 --- a/src/SMAPI.Web/Views/Mods/Index.cshtml +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -45,7 +45,10 @@
- {{visibleStats.total}} mods shown ({{Math.round((visibleStats.compatible + visibleStats.workaround) / visibleStats.total * 100)}}% compatible or have a workaround, {{Math.round((visibleStats.soon + visibleStats.broken) / visibleStats.total * 100)}}% broken, {{Math.round(visibleStats.abandoned / visibleStats.total * 100)}}% obsolete). +
+ {{visibleStats.total}} mods shown ({{Math.round((visibleStats.compatible + visibleStats.workaround) / visibleStats.total * 100)}}% compatible or have a workaround, {{Math.round((visibleStats.soon + visibleStats.broken) / visibleStats.total * 100)}}% broken, {{Math.round(visibleStats.abandoned / visibleStats.total * 100)}}% obsolete).
+ SMAPI 3.0 (upcoming): {{Math.round(visibleStats.smapi3_ok / visibleStats.total * 100)}}% ready, {{Math.round(visibleStats.smapi3_soon / visibleStats.total * 100)}}% soon, {{Math.round(visibleStats.smapi3_broken / visibleStats.total * 100)}}% broken, {{Math.round(visibleStats.smapi3_unknown / visibleStats.total * 100)}}% unknown. +
No matching mods found.
@@ -57,6 +60,7 @@ + @@ -88,6 +92,14 @@ sourceno source + diff --git a/src/SMAPI.Web/wwwroot/Content/js/mods.js b/src/SMAPI.Web/wwwroot/Content/js/mods.js index f7a8501e..23c7aa7e 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/mods.js +++ b/src/SMAPI.Web/wwwroot/Content/js/mods.js @@ -11,7 +11,11 @@ smapi.modList = function (mods) { soon: 0, broken: 0, abandoned: 0, - invalid: 0 + invalid: 0, + smapi3_unknown: 0, + smapi3_ok: 0, + smapi3_broken: 0, + smapi3_soon: 0 }; var data = { mods: mods, @@ -88,6 +92,28 @@ smapi.modList = function (mods) { id: "show-custom", value: true } + }, + "SMAPI 3.0": { + ok: { + label: "ready", + id: "show-smapi-3-ready", + value: true + }, + soon: { + label: "soon", + id: "show-smapi-3-soon", + value: true + }, + broken: { + label: "broken", + id: "show-smapi-3-broken", + value: true + }, + unknown: { + label: "unknown", + id: "show-smapi-3-unknown", + value: true + } } }, search: "" @@ -154,6 +180,7 @@ smapi.modList = function (mods) { if (mod.Visible) { stats.total++; stats[this.getCompatibilityGroup(mod)]++; + stats["smapi3_" + mod.Smapi3Status]++; } } }, @@ -179,6 +206,10 @@ smapi.modList = function (mods) { if (filters.status[status] && !filters.status[status].value) return false; + // check SMAPI 3.0 compatibility + if (filters["SMAPI 3.0"][mod.Smapi3Status] && !filters["SMAPI 3.0"][mod.Smapi3Status].value) + return false; + // check download sites var ignoreSites = []; diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs index c9d9f916..45b46ea6 100644 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/WebApi/ModExtendedMetadataModel.cs @@ -40,6 +40,15 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi /// The custom mod page URL (if applicable). public string CustomUrl { get; set; } + /**** + ** SMAPI 3.0 readiness + ****/ + /// Whether the mod is ready for the upcoming SMAPI 3.0. + public WikiSmapi3Status Smapi3Status { get; set; } + + /// A URL related to the . + public string Smapi3Url { get; set; } + /**** ** Stable compatibility ****/ @@ -85,6 +94,9 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.WebApi this.CustomSourceUrl = wiki.CustomSourceUrl; this.CustomUrl = wiki.CustomUrl; + this.Smapi3Status = wiki.Smapi3Status; + this.Smapi3Url = wiki.Smapi3Url; + this.CompatibilityStatus = wiki.Compatibility.Status; this.CompatibilitySummary = wiki.Compatibility.Summary; diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs index 91078b08..19a4292f 100644 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiClient.cs @@ -102,7 +102,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki // parse stable compatibility WikiCompatibilityInfo compatibility = new WikiCompatibilityInfo { - Status = this.GetAttributeAsStatus(node, "data-status") ?? WikiCompatibilityStatus.Ok, + Status = this.GetAttributeAsEnum(node, "data-status") ?? WikiCompatibilityStatus.Ok, BrokeIn = this.GetAttribute(node, "data-broke-in"), UnofficialVersion = this.GetAttributeAsSemanticVersion(node, "data-unofficial-version"), UnofficialUrl = this.GetAttribute(node, "data-unofficial-url"), @@ -112,7 +112,7 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki // parse beta compatibility WikiCompatibilityInfo betaCompatibility = null; { - WikiCompatibilityStatus? betaStatus = this.GetAttributeAsStatus(node, "data-beta-status"); + WikiCompatibilityStatus? betaStatus = this.GetAttributeAsEnum(node, "data-beta-status"); if (betaStatus.HasValue) { betaCompatibility = new WikiCompatibilityInfo @@ -126,6 +126,10 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki } } + // parse SMAPI 3.0 readiness status + WikiSmapi3Status smapi3Status = this.GetAttributeAsEnum(node, "data-smapi-3-status") ?? WikiSmapi3Status.Unknown; + string smapi3Url = this.GetAttribute(node, "data-smapi-3-url"); + // yield model yield return new WikiModEntry { @@ -140,6 +144,8 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki CustomUrl = customUrl, Compatibility = compatibility, BetaCompatibility = betaCompatibility, + Smapi3Status = smapi3Status, + Smapi3Url = smapi3Url, Warnings = warnings, Anchor = anchor }; @@ -169,17 +175,18 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki : new string[0]; } - /// Get an attribute value and parse it as a compatibility status. + /// Get an attribute value and parse it as an enum value. + /// The enum type. /// The element whose attributes to read. /// The attribute name. - private WikiCompatibilityStatus? GetAttributeAsStatus(HtmlNode element, string name) + private TEnum? GetAttributeAsEnum(HtmlNode element, string name) where TEnum : struct { string raw = this.GetAttribute(element, name); if (raw == null) return null; - if (!Enum.TryParse(raw, true, out WikiCompatibilityStatus status)) - throw new InvalidOperationException($"Unknown status '{raw}' when parsing compatibility list."); - return status; + if (!Enum.TryParse(raw, true, out TEnum value) && Enum.IsDefined(typeof(TEnum), value)) + throw new InvalidOperationException($"Unknown {typeof(TEnum).Name} value '{raw}' when parsing compatibility list."); + return value; } /// Get an attribute value and parse it as a semantic version. diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs index f7b7839b..b71269fe 100644 --- a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiModEntry.cs @@ -39,6 +39,12 @@ namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki /// The mod's compatibility with the latest beta version of the game (if any). public WikiCompatibilityInfo BetaCompatibility { get; set; } + /// Whether the mod is ready for the upcoming SMAPI 3.0. + public WikiSmapi3Status Smapi3Status { get; set; } + + /// A URL related to the . + public string Smapi3Url { 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 => this.BetaCompatibility != null; diff --git a/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiSmapi3Status.cs b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiSmapi3Status.cs new file mode 100644 index 00000000..879cfd8a --- /dev/null +++ b/src/StardewModdingAPI.Toolkit/Framework/Clients/Wiki/WikiSmapi3Status.cs @@ -0,0 +1,18 @@ +namespace StardewModdingAPI.Toolkit.Framework.Clients.Wiki +{ + /// Whether a mod is ready for the upcoming SMAPI 3.0. + public enum WikiSmapi3Status + { + /// The mod's compatibility status is unknown. + Unknown = 0, + + /// The mod is compatible with the upcoming SMAPI 3.0. + Ok = 1, + + /// The mod will break in SMAPI 3.0. + Broken = 2, + + /// The mod has a pull request submitted for SMAPI 3.0 compatibility. + Soon = 3 + } +} -- cgit From 39341d772e99492f239ad8aff09cca8760ff5b83 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Dec 2018 13:33:22 -0500 Subject: prevent invalid items from crashing the game --- docs/README.md | 6 ++-- docs/release-notes.md | 3 +- src/SMAPI/Framework/SCore.cs | 3 +- src/SMAPI/Patches/ObjectErrorPatch.cs | 55 +++++++++++++++++++++++++++++++++++ src/SMAPI/StardewModdingAPI.csproj | 1 + 5 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/SMAPI/Patches/ObjectErrorPatch.cs (limited to 'docs') diff --git a/docs/README.md b/docs/README.md index b8e3b50b..e4220de2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ -**SMAPI** is an open-source modding API for [Stardew Valley](https://stardewvalley.net/) that lets -you play the game with mods. It's safely installed alongside the game's executable, and doesn't -change any of your game files. It serves eight main purposes: +**SMAPI** is an open-source modding framework and API for [Stardew Valley](https://stardewvalley.net/) +that lets you play the game with mods. It's safely installed alongside the game's executable, and +doesn't change any of your game files. It serves eight main purposes: 1. **Load mods into the game.** _SMAPI loads mods when the game is starting up so they can interact with it. (Code mods aren't diff --git a/docs/release-notes.md b/docs/release-notes.md index fa7f4109..bcbdee22 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,7 @@ # Release notes ## Upcoming release * For players: + * SMAPI now prevents invalid items from crashing the game on hover. * Fixed cryptic error message when the game isn't installed correctly. * Fixed error when a mod makes invalid changes to an NPC schedule. * Fixed invalid NPC data propagated when a mod changes NPC dispositions. @@ -10,7 +11,7 @@ * For modders: * Added dedicated content pack API. - * **Deprecations:** + * **Deprecations:** * The `assetData.AsDictionary().Set` methods are deprecated and will be removed in SMAPI 3.0. Mods should access the `Data` property directly instead. * FOR SMAPI developers: diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 3bc0aca4..679838ba 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -184,7 +184,8 @@ namespace StardewModdingAPI.Framework // apply game patches new GamePatcher(this.Monitor).Apply( - new DialogueErrorPatch(this.MonitorForGame, this.Reflection) + new DialogueErrorPatch(this.MonitorForGame, this.Reflection), + new ObjectErrorPatch() ); } diff --git a/src/SMAPI/Patches/ObjectErrorPatch.cs b/src/SMAPI/Patches/ObjectErrorPatch.cs new file mode 100644 index 00000000..2cbb60c5 --- /dev/null +++ b/src/SMAPI/Patches/ObjectErrorPatch.cs @@ -0,0 +1,55 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Harmony; +using StardewModdingAPI.Framework.Patching; +using StardewValley; +using SObject = StardewValley.Object; + +namespace StardewModdingAPI.Patches +{ + /// A Harmony patch for which intercepts crashes due to the item no longer existing. + internal class ObjectErrorPatch : IHarmonyPatch + { + /********* + ** Accessors + *********/ + /// A unique name for this patch. + public string Name => $"{nameof(ObjectErrorPatch)}"; + + + /********* + ** Public methods + *********/ + /// Apply the Harmony patch. + /// The Harmony instance. + public void Apply(HarmonyInstance harmony) + { + MethodInfo method = AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)); + MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.Prefix)); + + harmony.Patch(method, new HarmonyMethod(prefix), null); + } + + + /********* + ** Private methods + *********/ + /// The method to call instead of . + /// 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 Prefix(SObject __instance, ref string __result) + { + // invalid bigcraftables crash instead of showing '???' like invalid non-bigcraftables + if (!__instance.IsRecipe && __instance.bigCraftable.Value && !Game1.bigCraftablesInformation.ContainsKey(__instance.ParentSheetIndex)) + { + __result = "???"; + return false; + } + + return false; + } + } +} diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 2c769f41..3f1a273d 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -326,6 +326,7 @@ + -- cgit From ce4593fb302ef8bfd6ddffe7e097d79ad7be132a Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 15 Dec 2018 14:46:09 -0500 Subject: update release notes --- docs/release-notes.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index bcbdee22..2e826350 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,9 +12,10 @@ * For modders: * Added dedicated content pack API. * **Deprecations:** - * The `assetData.AsDictionary().Set` methods are deprecated and will be removed in SMAPI 3.0. Mods should access the `Data` property directly instead. + * The `assetData.AsDictionary().Set` methods are now deprecated. Mods should access the `Data` property directly instead. + * The content pack methods directly on `helper` are now deprecated. Mods should use the new `helper.ContentPacks` API instead. -* FOR SMAPI developers: +* For SMAPI developers: * Added SMAPI 3.0 readiness to mod API data. ## 2.9.1 -- cgit From 803f9f439ca7547a5de100ee6564d295fa44cbf3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 16 Dec 2018 02:55:41 -0500 Subject: fix messages not sent correctly to farmhands connected via Steam friends --- docs/release-notes.md | 1 + src/SMAPI/Framework/Networking/SGalaxyNetServer.cs | 24 ++++++++++++++++------ src/SMAPI/Framework/SMultiplayer.cs | 2 ++ 3 files changed, 21 insertions(+), 6 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 2e826350..1f1dcab2 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## Upcoming release * For players: * SMAPI now prevents invalid items from crashing the game on hover. + * Fixed some multiplayer mod features not working when connecting via Steam friends. * Fixed cryptic error message when the game isn't installed correctly. * Fixed error when a mod makes invalid changes to an NPC schedule. * Fixed invalid NPC data propagated when a mod changes NPC dispositions. diff --git a/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs index 2fc92737..82d11938 100644 --- a/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs +++ b/src/SMAPI/Framework/Networking/SGalaxyNetServer.cs @@ -34,9 +34,14 @@ namespace StardewModdingAPI.Framework.Networking this.OnProcessingMessage = onProcessingMessage; } + + /********* + ** Protected methods + *********/ /// Read and process a message from the client. /// The Galaxy peer ID. /// The data to process. + /// This reimplements , but adds a callback to . [SuppressMessage("ReSharper", "AccessToDisposedClosure", Justification = "The callback is invoked synchronously.")] protected override void onReceiveMessage(GalaxyID peer, Stream messageStream) { @@ -44,20 +49,27 @@ namespace StardewModdingAPI.Framework.Networking using (BinaryReader reader = new BinaryReader(messageStream)) { message.Read(reader); - this.OnProcessingMessage(message, outgoing => this.sendMessage(peer, outgoing), () => + ulong peerID = peer.ToUint64(); // note: GalaxyID instances get reused, so need to store the underlying ID instead + this.OnProcessingMessage(message, outgoing => this.SendMessageToPeerID(peerID, outgoing), () => { - if (this.peers.ContainsLeft(message.FarmerID) && (long)this.peers[message.FarmerID] == (long)peer.ToUint64()) - { + if (this.peers.ContainsLeft(message.FarmerID) && (long)this.peers[message.FarmerID] == (long)peerID) this.gameServer.processIncomingMessage(message); - } else if (message.MessageType == StardewValley.Multiplayer.playerIntroduction) { NetFarmerRoot farmer = this.Multiplayer.readFarmer(message.Reader); - GalaxyID capturedPeer = new GalaxyID(peer.ToUint64()); - this.gameServer.checkFarmhandRequest(Convert.ToString(peer.ToUint64()), farmer, msg => this.sendMessage(capturedPeer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = capturedPeer.ToUint64()); + GalaxyID capturedPeer = new GalaxyID(peerID); + this.gameServer.checkFarmhandRequest(Convert.ToString(peerID), farmer, msg => this.sendMessage(capturedPeer, msg), () => this.peers[farmer.Value.UniqueMultiplayerID] = capturedPeer.ToUint64()); } }); } } + + /// Send a message to a remote peer. + /// The unique Galaxy ID, derived from . + /// The message to send. + private void SendMessageToPeerID(ulong peerID, OutgoingMessage message) + { + this.sendMessage(new GalaxyID(peerID), message); + } } } diff --git a/src/SMAPI/Framework/SMultiplayer.cs b/src/SMAPI/Framework/SMultiplayer.cs index 12cd2d46..784edae3 100644 --- a/src/SMAPI/Framework/SMultiplayer.cs +++ b/src/SMAPI/Framework/SMultiplayer.cs @@ -119,6 +119,7 @@ namespace StardewModdingAPI.Framework } default: + this.Monitor.Log($"Unknown multiplayer client type: {client.GetType().AssemblyQualifiedName}", LogLevel.Trace); return client; } } @@ -142,6 +143,7 @@ namespace StardewModdingAPI.Framework } default: + this.Monitor.Log($"Unknown multiplayer server type: {server.GetType().AssemblyQualifiedName}", LogLevel.Trace); return server; } } -- cgit From fd0af5f3c149629b91bbe1651a7bda9564b860eb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 16 Dec 2018 17:25:46 -0500 Subject: polish release notes --- docs/release-notes.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index 1f1dcab2..95de15ec 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,20 +1,20 @@ # Release notes -## Upcoming release +## 2.9.2 * For players: * SMAPI now prevents invalid items from crashing the game on hover. - * Fixed some multiplayer mod features not working when connecting via Steam friends. + * Fixed some multiplayer features broken when connecting via Steam friends. * Fixed cryptic error message when the game isn't installed correctly. * Fixed error when a mod makes invalid changes to an NPC schedule. - * Fixed invalid NPC data propagated when a mod changes NPC dispositions. - * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. - * Fixed game launch crash logged as `SMAPI` instead of `game`. + * Fixed game launch errors logged as `SMAPI` instead of `game`. * Fixed Windows installer adding unneeded Unix launcher to game folder. * For modders: - * Added dedicated content pack API. + * Moved content pack methods into a new [content pack API](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Content_Packs). + * Fixed invalid NPC data propagated when a mod changes NPC dispositions. + * Fixed `Display.RenderedWorld` event broken in SMAPI 2.9.1. * **Deprecations:** * The `assetData.AsDictionary().Set` methods are now deprecated. Mods should access the `Data` property directly instead. - * The content pack methods directly on `helper` are now deprecated. Mods should use the new `helper.ContentPacks` API instead. + * The content pack methods directly on `helper` are now deprecated. Mods should use `helper.ContentPacks` instead. * For SMAPI developers: * Added SMAPI 3.0 readiness to mod API data. -- cgit
compatibility broke in code3.0  
+ + #