From 1398e591abc23a7af927cc7de1e8df512b6fc598 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 9 Dec 2017 12:46:10 -0500 Subject: fix reflection API error with properties which don't have both get and set --- docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 4cf8efa2..26a43f66 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,4 +1,8 @@ # Release notes +## 2.3 +* For modders: + * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. + ## 2.2 * For players: * Fixed error when a mod loads custom assets on Linux/Mac. -- cgit From dd7b5ac462f5be2d6bee9d61f243e5c32140f175 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 10 Dec 2017 13:37:59 -0500 Subject: fix mods being able to change cursor position reported to other mods --- docs/release-notes.md | 1 + src/SMAPI/Events/EventArgsInput.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 26a43f66..16ed9af5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## 2.3 * For modders: * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. + * Fixed issue where a mod could change the cursor position reported to other mods. ## 2.2 * For players: diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs index 54ce9b53..ee15fd27 100644 --- a/src/SMAPI/Events/EventArgsInput.cs +++ b/src/SMAPI/Events/EventArgsInput.cs @@ -16,7 +16,7 @@ namespace StardewModdingAPI.Events public SButton Button { get; } /// The current cursor position. - public ICursorPosition Cursor { get; set; } + public ICursorPosition Cursor { get; } /// Whether the input is considered a 'click' by the game for enabling action. [Obsolete("Use " + nameof(EventArgsInput.IsActionButton) + " or " + nameof(EventArgsInput.IsUseToolButton) + " instead")] // deprecated in SMAPI 2.1 -- cgit From 2c5532f4ab0d0bf4ce5a4bc376cf8bb5fb803f11 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 10 Dec 2017 13:43:05 -0500 Subject: add e.IsSuppressed to input event args --- docs/release-notes.md | 1 + src/SMAPI/Events/EventArgsInput.cs | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 16ed9af5..02e75f3d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,7 @@ # Release notes ## 2.3 * For modders: + * Added `IsSuppressed` to input events so mods can optionally avoid handling a key another mod already handled. * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. * Fixed issue where a mod could change the cursor position reported to other mods. diff --git a/src/SMAPI/Events/EventArgsInput.cs b/src/SMAPI/Events/EventArgsInput.cs index ee15fd27..a5325b76 100644 --- a/src/SMAPI/Events/EventArgsInput.cs +++ b/src/SMAPI/Events/EventArgsInput.cs @@ -28,6 +28,9 @@ namespace StardewModdingAPI.Events /// Whether the input should use tools on the affected tile. public bool IsUseToolButton { get; } + /// Whether a mod has indicated the key was already handled. + public bool IsSuppressed { get; private set; } + /********* ** Public methods @@ -55,6 +58,9 @@ namespace StardewModdingAPI.Events /// The button to suppress. public void SuppressButton(SButton button) { + if (button == this.Button) + this.IsSuppressed = true; + // keyboard if (button.TryGetKeyboard(out Keys key)) Game1.oldKBState = new KeyboardState(Game1.oldKBState.GetPressedKeys().Union(new[] { key }).ToArray()); -- cgit From 80c4d93559989777fbe5a23b923155b93df7a715 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 10 Dec 2017 15:28:27 -0500 Subject: fix GraphicsEvents.OnPostRenderEvent not being raised in some cases --- docs/release-notes.md | 1 + src/SMAPI/Framework/SGame.cs | 74 +++++++++++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 28 deletions(-) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 02e75f3d..fa04c055 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## 2.3 * For modders: * Added `IsSuppressed` to input events so mods can optionally avoid handling a key another mod already handled. + * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. * Fixed issue where a mod could change the cursor position reported to other mods. diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index c886a4b7..3062b0f6 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -689,6 +689,7 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"The {activeClickableMenu.GetType().FullName} menu crashed while drawing itself during save. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); activeClickableMenu.exitThisMenu(); } + this.RaisePostRender(); Game1.spriteBatch.End(); } //base.Draw(gameTime); @@ -712,6 +713,7 @@ namespace StardewModdingAPI.Framework this.Monitor.Log($"The {Game1.activeClickableMenu.GetType().FullName} menu crashed while drawing itself. SMAPI will force it to exit to avoid crashing the game.\n{ex.GetLogSummary()}", LogLevel.Error); Game1.activeClickableMenu.exitThisMenu(); } + this.RaisePostRender(); Game1.spriteBatch.End(); if ((double)Game1.options.zoomLevel != 1.0) { @@ -721,11 +723,12 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } - if (Game1.overlayMenu == null) - return; - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); - Game1.overlayMenu.draw(Game1.spriteBatch); - Game1.spriteBatch.End(); + if (Game1.overlayMenu != null) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState) null, (RasterizerState) null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); + } } else if ((int)Game1.gameMode == 11) { @@ -733,6 +736,7 @@ namespace StardewModdingAPI.Framework 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); + this.RaisePostRender(); Game1.spriteBatch.End(); } else if (Game1.currentMinigame != null) @@ -744,6 +748,7 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * ((int)Game1.gameMode == 0 ? 1f - Game1.fadeToBlackAlpha : Game1.fadeToBlackAlpha)); Game1.spriteBatch.End(); } + this.RaisePostRender(needsNewBatch: true); if ((double)Game1.options.zoomLevel != 1.0) { this.GraphicsDevice.SetRenderTarget((RenderTarget2D)null); @@ -752,11 +757,12 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } - if (Game1.overlayMenu == null) - return; - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); - Game1.overlayMenu.draw(Game1.spriteBatch); - Game1.spriteBatch.End(); + if (Game1.overlayMenu != null) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState) null, (RasterizerState) null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); + } } else if (Game1.showingEndOfNightStuff) { @@ -775,6 +781,7 @@ namespace StardewModdingAPI.Framework Game1.activeClickableMenu.exitThisMenu(); } } + this.RaisePostRender(); Game1.spriteBatch.End(); if ((double)Game1.options.zoomLevel != 1.0) { @@ -784,11 +791,12 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } - if (Game1.overlayMenu == null) - return; - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); - Game1.overlayMenu.draw(Game1.spriteBatch); - Game1.spriteBatch.End(); + if (Game1.overlayMenu != null) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState) null, (RasterizerState) null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); + } } else if ((int)Game1.gameMode == 6) { @@ -806,6 +814,7 @@ namespace StardewModdingAPI.Framework int x = 64; int y = Game1.graphics.GraphicsDevice.Viewport.TitleSafeArea.Bottom - height; SpriteText.drawString(Game1.spriteBatch, s, x, y, 999999, widthOfString, height, 1f, 0.88f, false, 0, str5, -1); + this.RaisePostRender(); Game1.spriteBatch.End(); if ((double)Game1.options.zoomLevel != 1.0) { @@ -815,11 +824,12 @@ namespace StardewModdingAPI.Framework Game1.spriteBatch.Draw((Texture2D)this.screenWrapper, Vector2.Zero, new Microsoft.Xna.Framework.Rectangle?(this.screenWrapper.Bounds), Color.White, 0.0f, Vector2.Zero, Game1.options.zoomLevel, SpriteEffects.None, 1f); Game1.spriteBatch.End(); } - if (Game1.overlayMenu == null) - return; - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState)null, (RasterizerState)null); - Game1.overlayMenu.draw(Game1.spriteBatch); - Game1.spriteBatch.End(); + if (Game1.overlayMenu != null) + { + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, (DepthStencilState) null, (RasterizerState) null); + Game1.overlayMenu.draw(Game1.spriteBatch); + Game1.spriteBatch.End(); + } } else { @@ -1265,6 +1275,8 @@ namespace StardewModdingAPI.Framework } else if (Game1.farmEvent != null) Game1.farmEvent.drawAboveEverything(Game1.spriteBatch); + + this.RaisePostRender(); Game1.spriteBatch.End(); if (Game1.overlayMenu != null) { @@ -1272,14 +1284,6 @@ namespace StardewModdingAPI.Framework Game1.overlayMenu.draw(Game1.spriteBatch); Game1.spriteBatch.End(); } - - if (GraphicsEvents.HasPostRenderListeners()) - { - Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); - GraphicsEvents.InvokeOnPostRenderEvent(this.Monitor); - Game1.spriteBatch.End(); - } - this.renderScreenBuffer(); } } @@ -1401,5 +1405,19 @@ namespace StardewModdingAPI.Framework hash ^= v.GetHashCode(); return hash; } + + /// Raise the if there are any listeners. + /// Whether to create a new sprite batch. + private void RaisePostRender(bool needsNewBatch = false) + { + if (GraphicsEvents.HasPostRenderListeners()) + { + if (needsNewBatch) + Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null); + GraphicsEvents.InvokeOnPostRenderEvent(this.Monitor); + if (needsNewBatch) + Game1.spriteBatch.End(); + } + } } } -- cgit From 6bdd49af13ed6bdfef8220c85ca32bca904d3a1e Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 10 Dec 2017 23:27:10 -0500 Subject: detect libgdiplus-missing exception and show a friendly error instead (#408) --- docs/release-notes.md | 1 + src/SMAPI/Framework/InternalExtensions.cs | 9 +++++++++ src/SMAPI/Framework/SContentManager.cs | 4 +++- 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index fa04c055..a76b5e19 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,7 @@ * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. * Fixed issue where a mod could change the cursor position reported to other mods. + * Improved cryptic libgdiplus errors on Mac when Mono isn't installed. ## 2.2 * For players: diff --git a/src/SMAPI/Framework/InternalExtensions.cs b/src/SMAPI/Framework/InternalExtensions.cs index f81e05a9..bec6c183 100644 --- a/src/SMAPI/Framework/InternalExtensions.cs +++ b/src/SMAPI/Framework/InternalExtensions.cs @@ -108,6 +108,15 @@ namespace StardewModdingAPI.Framework } } + /// Get the lowest exception in an exception stack. + /// The exception from which to search. + public static Exception GetInnermostException(this Exception exception) + { + while (exception.InnerException != null) + exception = exception.InnerException; + return exception; + } + /**** ** Sprite batch ****/ diff --git a/src/SMAPI/Framework/SContentManager.cs b/src/SMAPI/Framework/SContentManager.cs index 1803098d..ebea6c84 100644 --- a/src/SMAPI/Framework/SContentManager.cs +++ b/src/SMAPI/Framework/SContentManager.cs @@ -205,7 +205,7 @@ namespace StardewModdingAPI.Framework return this.LoadImpl(assetName, instance); // load mod content - SContentLoadException GetContentError(string reasonPhrase) => new SContentLoadException($"Failed loading content asset '{assetName}': {reasonPhrase}."); + SContentLoadException GetContentError(string reasonPhrase) => new SContentLoadException($"Failed loading content asset '{assetName}': {reasonPhrase}"); try { return this.WithWriteLock(() => @@ -252,6 +252,8 @@ namespace StardewModdingAPI.Framework } catch (Exception ex) when (!(ex is SContentLoadException)) { + if (ex.GetInnermostException() is DllNotFoundException dllEx && dllEx.Message == "libgdiplus.dylib") + throw GetContentError("couldn't find libgdiplus, which is needed to load mod images. Make sure Mono is installed and you're running the game through the normal launcher."); throw new SContentLoadException($"The content manager failed loading content asset '{assetName}'.", ex); } } -- cgit From d3f6f9c70a0435a505d95a45b9bca2be2d71caaf Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 10 Dec 2017 23:42:22 -0500 Subject: fix log parser favicon (#405) --- docs/release-notes.md | 3 +++ src/SMAPI.Web/Startup.cs | 1 + 2 files changed, 4 insertions(+) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index a76b5e19..57d9c480 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -7,6 +7,9 @@ * Fixed issue where a mod could change the cursor position reported to other mods. * Improved cryptic libgdiplus errors on Mac when Mono isn't installed. +* For the [log parser][]: + * Fixed broken favicon. + ## 2.2 * For players: * Fixed error when a mod loads custom assets on Linux/Mac. diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index 16952124..2f2b0d11 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -89,6 +89,7 @@ namespace StardewModdingAPI.Web req.Host.Host != "localhost" && (req.Host.Host.StartsWith("api.") || req.Host.Host.StartsWith("log.")) && !req.Path.StartsWithSegments("/content") + && !req.Path.StartsWithSegments("/favicon.ico") )) // shortcut redirects -- cgit From 69c9ab0ecd184e4706a8e6394b38fa592cb808d0 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 11 Dec 2017 21:29:39 -0500 Subject: trace mods with no update keys, tweak update-check logging --- docs/release-notes.md | 1 + src/SMAPI/Program.cs | 160 ++++++++++++++++++++++++++------------------------ 2 files changed, 84 insertions(+), 77 deletions(-) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 57d9c480..0e2477f4 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ ## 2.3 * For modders: * Added `IsSuppressed` to input events so mods can optionally avoid handling a key another mod already handled. + * Added trace message listing mods with no update keys. * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. * Fixed issue where a mod could change the cursor position reported to other mods. diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 7bfb0abd..8bc2c675 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -500,12 +500,11 @@ namespace StardewModdingAPI { // create client WebApiClient client = new WebApiClient(this.Settings.WebApiBaseUrl, Constants.ApiVersion); + this.Monitor.Log("Checking for updates...", LogLevel.Trace); // check SMAPI version try { - this.Monitor.Log("Checking for SMAPI update...", LogLevel.Trace); - ModInfoModel response = client.GetModInfo($"GitHub:{this.Settings.GitHubProjectName}").Single().Value; if (response.Error != null) { @@ -515,7 +514,7 @@ namespace StardewModdingAPI else if (new SemanticVersion(response.Version).IsNewerThan(Constants.ApiVersion)) this.Monitor.Log($"You can update SMAPI to {response.Version}: {response.Url}", LogLevel.Alert); else - this.VerboseLog(" OK."); + this.Monitor.Log(" SMAPI okay.", LogLevel.Trace); } catch (Exception ex) { @@ -527,95 +526,102 @@ namespace StardewModdingAPI } // check mod versions - try + if (mods.Any()) { - // log issues - if (this.Settings.VerboseLogging) + try { - this.VerboseLog("Validating mod update keys..."); - foreach (IModMetadata mod in mods) + // prepare update keys + Dictionary modsByKey = + ( + from mod in mods + where mod.Manifest?.UpdateKeys != null + from key in mod.Manifest.UpdateKeys + select new { key, mod } + ) + .GroupBy(p => p.key, StringComparer.InvariantCultureIgnoreCase) + .ToDictionary( + group => group.Key, + group => group.Select(p => p.mod).ToArray(), + StringComparer.InvariantCultureIgnoreCase + ); + + // report update keys { - if (mod.Manifest == null) - this.VerboseLog($" {mod.DisplayName}: no manifest."); - else if (mod.Manifest.UpdateKeys == null || !mod.Manifest.UpdateKeys.Any()) - this.VerboseLog($" {mod.DisplayName}: no update keys."); + IModMetadata[] modsWithoutKeys = ( + from mod in mods + where + mod.Manifest != null + && (mod.Manifest.UpdateKeys == null || !mod.Manifest.UpdateKeys.Any()) + && (mod.Manifest?.UniqueID != "SMAPI.ConsoleCommands" && mod.Manifest?.UniqueID != "SMAPI.TrainerMod") + orderby mod.DisplayName + select mod + ).ToArray(); + + string message = $"Checking {modsByKey.Count} mod update keys."; + if (modsWithoutKeys.Any()) + message += $" {modsWithoutKeys.Length} mods have no update keys: {string.Join(", ", modsWithoutKeys.Select(p => p.DisplayName))}."; + this.Monitor.Log($" {message}", LogLevel.Trace); } - } - // prepare update keys - Dictionary modsByKey = - ( - from mod in mods - where mod.Manifest?.UpdateKeys != null - from key in mod.Manifest.UpdateKeys - select new { key, mod } - ) - .GroupBy(p => p.key, StringComparer.InvariantCultureIgnoreCase) - .ToDictionary( - group => group.Key, - group => group.Select(p => p.mod).ToArray(), - StringComparer.InvariantCultureIgnoreCase - ); + // fetch results + var results = + ( + from entry in client.GetModInfo(modsByKey.Keys.ToArray()) + from mod in modsByKey[entry.Key] + orderby mod.DisplayName + select new { entry.Key, Mod = mod, Info = entry.Value } + ) + .ToArray(); + + // extract latest versions + IDictionary updatesByMod = new Dictionary(); + foreach (var result in results) + { + IModMetadata mod = result.Mod; + ModInfoModel info = result.Info; - // fetch results - this.Monitor.Log($"Checking for updates to {modsByKey.Keys.Count} keys...", LogLevel.Trace); - var results = - ( - from entry in client.GetModInfo(modsByKey.Keys.ToArray()) - from mod in modsByKey[entry.Key] - orderby mod.DisplayName - select new { entry.Key, Mod = mod, Info = entry.Value } - ) - .ToArray(); - - // extract latest versions - IDictionary updatesByMod = new Dictionary(); - foreach (var result in results) - { - IModMetadata mod = result.Mod; - ModInfoModel info = result.Info; + // handle error + if (info.Error != null) + { + this.Monitor.Log($" {mod.DisplayName} ({result.Key}): update error: {info.Error}", LogLevel.Trace); + continue; + } - // handle error - if (info.Error != null) - { - this.Monitor.Log($" {mod.DisplayName} ({result.Key}): update error: {info.Error}", LogLevel.Trace); - continue; + // track update + ISemanticVersion localVersion = mod.DataRecord != null + ? new SemanticVersion(mod.DataRecord.GetLocalVersionForUpdateChecks(mod.Manifest.Version.ToString())) + : mod.Manifest.Version; + ISemanticVersion latestVersion = new SemanticVersion(mod.DataRecord != null + ? mod.DataRecord.GetRemoteVersionForUpdateChecks(new SemanticVersion(info.Version).ToString()) + : info.Version + ); + bool isUpdate = latestVersion.IsNewerThan(localVersion); + this.VerboseLog($" {mod.DisplayName} ({result.Key}): {(isUpdate ? $"{mod.Manifest.Version}{(!localVersion.Equals(mod.Manifest.Version) ? $" [{localVersion}]" : "")} => {info.Version}{(!latestVersion.Equals(new SemanticVersion(info.Version)) ? $" [{latestVersion}]" : "")}" : "okay")}."); + if (isUpdate) + { + if (!updatesByMod.TryGetValue(mod, out ModInfoModel other) || latestVersion.IsNewerThan(other.Version)) + updatesByMod[mod] = info; + } } - // track update - ISemanticVersion localVersion = mod.DataRecord != null - ? new SemanticVersion(mod.DataRecord.GetLocalVersionForUpdateChecks(mod.Manifest.Version.ToString())) - : mod.Manifest.Version; - ISemanticVersion latestVersion = new SemanticVersion(mod.DataRecord != null - ? mod.DataRecord.GetRemoteVersionForUpdateChecks(new SemanticVersion(info.Version).ToString()) - : info.Version - ); - bool isUpdate = latestVersion.IsNewerThan(localVersion); - this.VerboseLog($" {mod.DisplayName} ({result.Key}): {(isUpdate ? $"{mod.Manifest.Version}{(!localVersion.Equals(mod.Manifest.Version) ? $" [{localVersion}]" : "")} => {info.Version}{(!latestVersion.Equals(new SemanticVersion(info.Version)) ? $" [{latestVersion}]" : "")}" : "OK")}."); - if (isUpdate) + // output + if (updatesByMod.Any()) { - if (!updatesByMod.TryGetValue(mod, out ModInfoModel other) || latestVersion.IsNewerThan(other.Version)) - updatesByMod[mod] = info; + this.Monitor.Newline(); + this.Monitor.Log($"You can update {updatesByMod.Count} mod{(updatesByMod.Count != 1 ? "s" : "")}:", LogLevel.Alert); + foreach (var entry in updatesByMod.OrderBy(p => p.Key.DisplayName)) + this.Monitor.Log($" {entry.Key.DisplayName} {entry.Value.Version}: {entry.Value.Url}", LogLevel.Alert); } } - - // output - if (updatesByMod.Any()) + catch (Exception ex) { - this.Monitor.Newline(); - this.Monitor.Log($"You can update {updatesByMod.Count} mod{(updatesByMod.Count != 1 ? "s" : "")}:", LogLevel.Alert); - foreach (var entry in updatesByMod.OrderBy(p => p.Key.DisplayName)) - this.Monitor.Log($" {entry.Key.DisplayName} {entry.Value.Version}: {entry.Value.Url}", LogLevel.Alert); + this.Monitor.Log("Couldn't check for new mod versions. This won't affect your game, but you won't be notified of mod updates if this keeps happening.", LogLevel.Warn); + this.Monitor.Log(ex is WebException && ex.InnerException == null + ? ex.Message + : ex.ToString() + ); } } - catch (Exception ex) - { - this.Monitor.Log("Couldn't check for new mod versions. This won't affect your game, but you won't be notified of mod updates if this keeps happening.", LogLevel.Warn); - this.Monitor.Log(ex is WebException && ex.InnerException == null - ? ex.Message - : ex.ToString() - ); - } }).Start(); } -- cgit From a391dfe26372714a395abc5ee77b603e29562691 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 12 Dec 2017 01:58:42 -0500 Subject: update release notes (#409) --- docs/release-notes.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 0e2477f4..8407455c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,8 @@ # Release notes ## 2.3 * For modders: + * **Added mod-provided APIs** which enable simple integrations between mods, even without direct assembly references. + * Added `GameEvents.FirstUpdateTick` event, which is called once after all mods are initialised. * Added `IsSuppressed` to input events so mods can optionally avoid handling a key another mod already handled. * Added trace message listing mods with no update keys. * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. -- cgit From c3d0ce7245b76d26ea22ceb5430ee526d43170f7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 16 Dec 2017 17:41:16 -0500 Subject: mark TrainerMod as obsolete (replaced by ConsoleCommands) --- docs/release-notes.md | 1 + src/SMAPI/StardewModdingAPI.config.json | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 8407455c..c11ee46f 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -8,6 +8,7 @@ * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. * Fixed issue where a mod could change the cursor position reported to other mods. + * Updated compatibility list. * Improved cryptic libgdiplus errors on Mac when Mono isn't installed. * For the [log parser][]: diff --git a/src/SMAPI/StardewModdingAPI.config.json b/src/SMAPI/StardewModdingAPI.config.json index 6718806e..18a9f978 100644 --- a/src/SMAPI/StardewModdingAPI.config.json +++ b/src/SMAPI/StardewModdingAPI.config.json @@ -1890,6 +1890,16 @@ This file contains advanced configuration for SMAPI. You generally shouldn't cha "ID": "BlueMod_TractorMod | PhthaloBlue.TractorMod | community.TractorMod | Pathoschild.TractorMod", // changed in 3.2, 4.0 beta, and 4.0 "UpdateKeys": [ "Nexus:1401" ] }, + { + // TrainerMod + "ID": "SMAPI.TrainerMod", + "Compatibility": { + "~": { + "Status": "Obsolete", + "ReasonPhrase": "replaced by ConsoleCommands, which is added by the SMAPI installer." + } + } + }, { // Tree Transplant "ID": "TreeTransplant", -- cgit From 060418ab55cd598ea8af65cb2f167e098db00681 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 25 Dec 2017 11:19:32 -0500 Subject: update release notes (#411) --- docs/release-notes.md | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index c11ee46f..c1d2f9d3 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,5 +1,8 @@ # Release notes ## 2.3 +* For players: + * Added a user-friendly [download page](https://smapi.io). + * For modders: * **Added mod-provided APIs** which enable simple integrations between mods, even without direct assembly references. * Added `GameEvents.FirstUpdateTick` event, which is called once after all mods are initialised. -- cgit From e9b7223122cea893e017a2947ba73058126310b3 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 25 Dec 2017 11:24:47 -0500 Subject: polish release notes --- docs/release-notes.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index c1d2f9d3..254af4d9 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,17 +2,18 @@ ## 2.3 * For players: * Added a user-friendly [download page](https://smapi.io). + * Improved cryptic libgdiplus errors on Mac when Mono isn't installed. + * Fixed mod UIs hidden when menu backgrounds are enabled. * For modders: - * **Added mod-provided APIs** which enable simple integrations between mods, even without direct assembly references. - * Added `GameEvents.FirstUpdateTick` event, which is called once after all mods are initialised. - * Added `IsSuppressed` to input events so mods can optionally avoid handling a key another mod already handled. - * Added trace message listing mods with no update keys. + * **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 `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. * Fixed `GraphicsEvents.OnPostRenderEvent` not being raised in some specialised cases. - * Fixed error when using the reflection API accesses with a property with either `get` and `set` missing. + * 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. - * Improved cryptic libgdiplus errors on Mac when Mono isn't installed. * For the [log parser][]: * Fixed broken favicon. -- cgit From 70d7f44ce058ecbb402371ede2631977b43cd3e5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 25 Dec 2017 23:45:17 -0500 Subject: add missing release note --- docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs/release-notes.md') diff --git a/docs/release-notes.md b/docs/release-notes.md index 254af4d9..165e7d4e 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -10,6 +10,7 @@ * Added `GameEvents.FirstUpdateTick` event (called once after all mods are initialised). * 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 reflection API error for properties missing a `get` and `set`. * Fixed issue where a mod could change the cursor position reported to other mods. -- cgit