From 7992b52f035be5c6229ff0912bfd91084d41d5dc Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 31 Jul 2017 23:18:49 -0400 Subject: fix AfterDayStarted event being raised during the new-game intro (#332) --- src/StardewModdingAPI/Framework/SGame.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/StardewModdingAPI/Framework/SGame.cs') diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index d6f1a05b..bec6538b 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -19,7 +19,6 @@ using StardewValley.Menus; using StardewValley.Tools; using xTile.Dimensions; using xTile.Layers; -using SFarmer = StardewValley.Farmer; namespace StardewModdingAPI.Framework { @@ -318,6 +317,11 @@ namespace StardewModdingAPI.Framework *********/ if (Context.IsSaveLoaded && !SaveGame.IsProcessing /*still loading save*/ && this.AfterLoadTimer >= 0) { +#if !SMAPI_1_x + if (Game1.dayOfMonth != 0) // wait until new-game intro finishes (world not fully initialised yet) +#endif + this.AfterLoadTimer--; + if (this.AfterLoadTimer == 0) { this.Monitor.Log($"Context: loaded saved game '{Constants.SaveFolderName}', starting {Game1.currentSeason} {Game1.dayOfMonth} Y{Game1.year}.", LogLevel.Trace); @@ -329,7 +333,6 @@ namespace StardewModdingAPI.Framework #endif TimeEvents.InvokeAfterDayStarted(this.Monitor); } - this.AfterLoadTimer--; } /********* -- cgit From 9b22f3e004b35f66d9be6af211f20fe126fae209 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 31 Jul 2017 23:48:53 -0400 Subject: fix GraphicsEvents.Resize being raised before the game updates its window data (#328) --- release-notes.md | 3 ++- src/StardewModdingAPI/Events/GraphicsEvents.cs | 6 ++---- src/StardewModdingAPI/Framework/SGame.cs | 23 ++++++++++++++++++----- src/StardewModdingAPI/Program.cs | 1 - 4 files changed, 22 insertions(+), 11 deletions(-) (limited to 'src/StardewModdingAPI/Framework/SGame.cs') diff --git a/release-notes.md b/release-notes.md index 4da9132d..14d0179c 100644 --- a/release-notes.md +++ b/release-notes.md @@ -22,7 +22,8 @@ For mod developers: * Removed support for mods with no `Name`, `Version`, or `UniqueID` in their manifest. * Removed support for mods with a non-unique `UniqueID` value in their manifest. * Restrict mods from accessing SMAPI internals using its reflection helper, to discourage fragile mods. -* Fixed issue where `TimeEvents.AfterDayStarted` was raised during the new-game intro. +* Fixed `GraphicsEvents.Resize` being raised before the game updates its window data. +* Fixed `TimeEvents.AfterDayStarted` being raised during the new-game intro. ## 1.15.2 For players: diff --git a/src/StardewModdingAPI/Events/GraphicsEvents.cs b/src/StardewModdingAPI/Events/GraphicsEvents.cs index 25b976f1..fff51bed 100644 --- a/src/StardewModdingAPI/Events/GraphicsEvents.cs +++ b/src/StardewModdingAPI/Events/GraphicsEvents.cs @@ -51,11 +51,9 @@ namespace StardewModdingAPI.Events ****/ /// Raise a event. /// Encapsulates monitoring and logging. - /// The object which raised the event. - /// The event arguments. - internal static void InvokeResize(IMonitor monitor, object sender, EventArgs e) + internal static void InvokeResize(IMonitor monitor) { - monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.Resize)}", GraphicsEvents.Resize?.GetInvocationList(), sender, e); + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.Resize)}", GraphicsEvents.Resize?.GetInvocationList()); } /**** diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index bec6538b..65191931 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -53,10 +53,6 @@ namespace StardewModdingAPI.Framework /// Whether the game is saving and SMAPI has already raised . private bool IsBetweenSaveEvents; - /// Whether the game's zoom level is at 100% (i.e. nothing should be scaled). - public bool ZoomLevelIsOne => Game1.options.zoomLevel.Equals(1.0f); - - /**** ** Game state ****/ @@ -75,7 +71,10 @@ namespace StardewModdingAPI.Framework /// The previous mouse position on the screen adjusted for the zoom level. private Point PreviousMousePosition; - /// The previous save ID at last check. + /// The window size value at last check. + private Point PreviousWindowSize; + + /// The save ID at last check. private ulong PreviousSaveID; /// A hash of at last check. @@ -352,6 +351,20 @@ namespace StardewModdingAPI.Framework SaveEvents.InvokeAfterReturnToTitle(this.Monitor); } + /********* + ** Window events + *********/ + // Here we depend on the game's viewport instead of listening to the Window.Resize + // event because we need to notify mods after the game handles the resize, so the + // game's metadata (like Game1.viewport) are updated. That's a bit complicated + // since the game adds & removes its own handler on the fly. + if (Game1.viewport.Width != this.PreviousWindowSize.X || Game1.viewport.Height != this.PreviousWindowSize.Y) + { + Point size = new Point(Game1.viewport.Width, Game1.viewport.Height); + GraphicsEvents.InvokeResize(this.Monitor); + this.PreviousWindowSize = size; + } + /********* ** Input events (if window has focus) *********/ diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index b51917d9..0e1930ac 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -185,7 +185,6 @@ namespace StardewModdingAPI ((Form)Control.FromHandle(this.GameInstance.Window.Handle)).FormClosing += (sender, args) => this.Dispose(); #endif this.GameInstance.Exiting += (sender, e) => this.Dispose(); - this.GameInstance.Window.ClientSizeChanged += (sender, e) => GraphicsEvents.InvokeResize(this.Monitor, sender, e); GameEvents.InitializeInternal += (sender, e) => this.InitialiseAfterGameStart(); GameEvents.GameLoadedInternal += (sender, e) => this.CheckForUpdateAsync(); ContentEvents.AfterLocaleChanged += (sender, e) => this.OnLocaleChanged(); -- cgit From dafebd1626b6c3b34a818f5f161289a6e32fe4af Mon Sep 17 00:00:00 2001 From: spacechase0 Date: Wed, 9 Aug 2017 16:40:10 -0400 Subject: Fix building SMAPI 1.x --- src/StardewModdingAPI/Framework/SGame.cs | 3 +++ src/StardewModdingAPI/Utilities/SDate.cs | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src/StardewModdingAPI/Framework/SGame.cs') diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 65191931..755f0274 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -19,6 +19,9 @@ using StardewValley.Menus; using StardewValley.Tools; using xTile.Dimensions; using xTile.Layers; +#if SMAPI_1_x +using SFarmer = StardewValley.Farmer; +#endif namespace StardewModdingAPI.Framework { diff --git a/src/StardewModdingAPI/Utilities/SDate.cs b/src/StardewModdingAPI/Utilities/SDate.cs index bc3a2b38..d7631598 100644 --- a/src/StardewModdingAPI/Utilities/SDate.cs +++ b/src/StardewModdingAPI/Utilities/SDate.cs @@ -69,7 +69,9 @@ namespace StardewModdingAPI.Utilities this.Day = day; this.Season = season; this.Year = year; +#if !SMAPI_1_x this.DayOfWeek = this.GetDayOfWeek(); +#endif } /// Get the current in-game date. -- cgit From 723ddc255e1c2b399dfb734306fd00912a741e62 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 17 Aug 2017 17:46:45 -0400 Subject: break loops when loading assets through a mod loader --- src/StardewModdingAPI/Framework/Countdown.cs | 44 --------------- src/StardewModdingAPI/Framework/SContentManager.cs | 22 ++++++-- src/StardewModdingAPI/Framework/SGame.cs | 5 +- .../Framework/Utilities/ContextHash.cs | 62 ++++++++++++++++++++++ .../Framework/Utilities/Countdown.cs | 44 +++++++++++++++ src/StardewModdingAPI/StardewModdingAPI.csproj | 5 +- 6 files changed, 130 insertions(+), 52 deletions(-) delete mode 100644 src/StardewModdingAPI/Framework/Countdown.cs create mode 100644 src/StardewModdingAPI/Framework/Utilities/ContextHash.cs create mode 100644 src/StardewModdingAPI/Framework/Utilities/Countdown.cs (limited to 'src/StardewModdingAPI/Framework/SGame.cs') diff --git a/src/StardewModdingAPI/Framework/Countdown.cs b/src/StardewModdingAPI/Framework/Countdown.cs deleted file mode 100644 index 25ca2546..00000000 --- a/src/StardewModdingAPI/Framework/Countdown.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace StardewModdingAPI.Framework -{ - /// Counts down from a baseline value. - internal class Countdown - { - /********* - ** Accessors - *********/ - /// The initial value from which to count down. - public int Initial { get; } - - /// The current value. - public int Current { get; private set; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// The initial value from which to count down. - public Countdown(int initial) - { - this.Initial = initial; - this.Current = initial; - } - - /// Reduce the current value by one. - /// Returns whether the value was decremented (i.e. wasn't already zero). - public bool Decrement() - { - if (this.Current <= 0) - return false; - - this.Current--; - return true; - } - - /// Restart the countdown. - public void Reset() - { - this.Current = this.Initial; - } - } -} diff --git a/src/StardewModdingAPI/Framework/SContentManager.cs b/src/StardewModdingAPI/Framework/SContentManager.cs index 9e086870..25775291 100644 --- a/src/StardewModdingAPI/Framework/SContentManager.cs +++ b/src/StardewModdingAPI/Framework/SContentManager.cs @@ -9,6 +9,7 @@ using Microsoft.Xna.Framework.Content; using StardewModdingAPI.AssemblyRewriters; using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.Reflection; +using StardewModdingAPI.Framework.Utilities; using StardewModdingAPI.Metadata; using StardewValley; @@ -44,6 +45,9 @@ namespace StardewModdingAPI.Framework /// Provides metadata for core game assets. private readonly CoreAssets CoreAssets; + /// The assets currently being intercepted by instances. This is used to prevent infinite loops when a loader loads a new asset. + private readonly ContextHash AssetsBeingLoaded = new ContextHash(); + /********* ** Accessors @@ -139,11 +143,21 @@ namespace StardewModdingAPI.Framework // load asset T data; + if (this.AssetsBeingLoaded.Contains(assetName)) { - IAssetInfo info = new AssetInfo(this.GetLocale(), assetName, typeof(T), this.NormaliseAssetName); - IAssetData asset = this.ApplyLoader(info) ?? new AssetDataForObject(info, base.Load(assetName), this.NormaliseAssetName); - asset = this.ApplyEditors(info, asset); - data = (T)asset.Data; + this.Monitor.Log($"Broke loop while loading asset '{assetName}'.", LogLevel.Warn); + this.Monitor.Log($"Bypassing mod loaders for this asset. Stack trace:\n{Environment.StackTrace}", LogLevel.Trace); + data = base.Load(assetName); + } + else + { + data = this.AssetsBeingLoaded.Track(assetName, () => + { + IAssetInfo info = new AssetInfo(this.GetLocale(), assetName, typeof(T), this.NormaliseAssetName); + IAssetData asset = this.ApplyLoader(info) ?? new AssetDataForObject(info, base.Load(assetName), this.NormaliseAssetName); + asset = this.ApplyEditors(info, asset); + return (T)asset.Data; + }); } // update cache & return data diff --git a/src/StardewModdingAPI/Framework/SGame.cs b/src/StardewModdingAPI/Framework/SGame.cs index 755f0274..997e0c8c 100644 --- a/src/StardewModdingAPI/Framework/SGame.cs +++ b/src/StardewModdingAPI/Framework/SGame.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -11,6 +11,7 @@ using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using StardewModdingAPI.Events; using StardewModdingAPI.Framework.Reflection; +using StardewModdingAPI.Framework.Utilities; using StardewModdingAPI.Utilities; using StardewValley; using StardewValley.BellsAndWhistles; @@ -322,7 +323,7 @@ namespace StardewModdingAPI.Framework #if !SMAPI_1_x if (Game1.dayOfMonth != 0) // wait until new-game intro finishes (world not fully initialised yet) #endif - this.AfterLoadTimer--; + this.AfterLoadTimer--; if (this.AfterLoadTimer == 0) { diff --git a/src/StardewModdingAPI/Framework/Utilities/ContextHash.cs b/src/StardewModdingAPI/Framework/Utilities/ContextHash.cs new file mode 100644 index 00000000..0d8487bb --- /dev/null +++ b/src/StardewModdingAPI/Framework/Utilities/ContextHash.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace StardewModdingAPI.Framework.Utilities +{ + /// A wrapper meant for tracking recursive contexts. + /// The key type. + internal class ContextHash : HashSet + { + /********* + ** Public methods + *********/ + /// Construct an instance. + public ContextHash() { } + + /// Construct an instance. + /// The implementation to use when comparing values in the set, or null to use the default comparer for the set type. + public ContextHash(IEqualityComparer comparer) + : base(comparer) { } + + /// Add a key while an action is in progress, and remove it when it completes. + /// The key to add. + /// The action to perform. + /// The specified key is already added. + public void Track(T key, Action action) + { + if(this.Contains(key)) + throw new InvalidOperationException($"Can't track context for key {key} because it's already added."); + + this.Add(key); + try + { + action(); + } + finally + { + this.Remove(key); + } + } + + /// Add a key while an action is in progress, and remove it when it completes. + /// The value type returned by the method. + /// The key to add. + /// The action to perform. + public TResult Track(T key, Func action) + { + if (this.Contains(key)) + throw new InvalidOperationException($"Can't track context for key {key} because it's already added."); + + this.Add(key); + try + { + return action(); + } + finally + { + this.Remove(key); + } + } + } +} diff --git a/src/StardewModdingAPI/Framework/Utilities/Countdown.cs b/src/StardewModdingAPI/Framework/Utilities/Countdown.cs new file mode 100644 index 00000000..921a35ce --- /dev/null +++ b/src/StardewModdingAPI/Framework/Utilities/Countdown.cs @@ -0,0 +1,44 @@ +namespace StardewModdingAPI.Framework.Utilities +{ + /// Counts down from a baseline value. + internal class Countdown + { + /********* + ** Accessors + *********/ + /// The initial value from which to count down. + public int Initial { get; } + + /// The current value. + public int Current { get; private set; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The initial value from which to count down. + public Countdown(int initial) + { + this.Initial = initial; + this.Current = initial; + } + + /// Reduce the current value by one. + /// Returns whether the value was decremented (i.e. wasn't already zero). + public bool Decrement() + { + if (this.Current <= 0) + return false; + + this.Current--; + return true; + } + + /// Restart the countdown. + public void Reset() + { + this.Current = this.Initial; + } + } +} diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index d7e10ca5..73112983 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -1,4 +1,4 @@ - + @@ -91,6 +91,7 @@ Properties\GlobalAssemblyInfo.cs + @@ -126,7 +127,7 @@ - + -- cgit