diff options
-rw-r--r-- | docs/release-notes.md | 3 | ||||
-rw-r--r-- | src/SMAPI/Events/SpecialisedEvents.cs | 26 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 5 | ||||
-rw-r--r-- | src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs | 7 | ||||
-rw-r--r-- | src/SMAPI/Framework/SGame.cs | 6 | ||||
-rw-r--r-- | src/SMAPI/Metadata/InstructionMetadata.cs | 1 | ||||
-rw-r--r-- | src/SMAPI/StardewModdingAPI.csproj | 3 |
7 files changed, 46 insertions, 5 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md index f2dde81d..597fe0e5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,8 +9,9 @@ * Updated compatibility list and enabled update checks for more mods. * For modders: - * Added APIs to fetch and interact with content packs. + * Added content pack APIs. * Added support for `ISemanticVersion` in JSON models. + * Added `SpecialisedEvents.UnvalidatedUpdateTick` event for specialised use cases. * Fixed deadlock in rare cases when injecting a file with an asset loader. * Fixed unhelpful error when a mod exposes a non-public API. * Fixed input events being raised for keyboard buttons when a textbox is receiving input. diff --git a/src/SMAPI/Events/SpecialisedEvents.cs b/src/SMAPI/Events/SpecialisedEvents.cs new file mode 100644 index 00000000..2a36e6e4 --- /dev/null +++ b/src/SMAPI/Events/SpecialisedEvents.cs @@ -0,0 +1,26 @@ +using System; +using StardewModdingAPI.Framework; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events serving specialised edge cases that shouldn't be used by most mod.</summary> + public static class SpecialisedEvents + { + /********* + ** Events + *********/ + /// <summary>Raised when the game updates its state (≈60 times per second), regardless of normal SMAPI validation. This event is not thread-safe and may be invoked while game logic is running asynchronously. Changes to game state in this method may crash the game or corrupt an in-progress save. Do not use this event unless you're fully aware of the context in which your code will be run. Mods using this method will trigger a stability warning in the SMAPI console.</summary> + public static event EventHandler UnvalidatedUpdateTick; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise an <see cref="UnvalidatedUpdateTick"/> event.</summary> + /// <param name="monitor">Encapsulates logging and monitoring.</param> + internal static void InvokeUnvalidatedUpdateTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(SpecialisedEvents)}.{nameof(SpecialisedEvents.UnvalidatedUpdateTick)}", SpecialisedEvents.UnvalidatedUpdateTick?.GetInvocationList()); + } + } +} diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 3a7b214a..ccbd053e 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -285,6 +285,11 @@ namespace StardewModdingAPI.Framework.ModLoading this.Monitor.LogOnce(loggedMessages, $"{mod.DisplayName} seems to change the save serialiser. It may change your saves in such a way that they won't work without this mod in the future.", LogLevel.Warn); break; + case InstructionHandleResult.DetectedUnvalidatedUpdateTick: + this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected reference to {handler.NounPhrase} in assembly {filename}."); + this.Monitor.LogOnce(loggedMessages, $"{mod.DisplayName} uses a specialised SMAPI event that may crash the game or corrupt your save file. If you encounter problems, try removing this mod first.", LogLevel.Warn); + break; + case InstructionHandleResult.DetectedDynamic: this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected 'dynamic' keyword ({handler.NounPhrase}) in assembly {filename}."); this.Monitor.LogOnce(loggedMessages, $"{mod.DisplayName} uses the 'dynamic' keyword, which isn't compatible with Stardew Valley on Linux or Mac.", diff --git a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs index 0ae598fc..6a7e0519 100644 --- a/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs +++ b/src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs @@ -1,3 +1,5 @@ +using StardewModdingAPI.Events; + namespace StardewModdingAPI.Framework.ModLoading { /// <summary>Indicates how an instruction was handled.</summary> @@ -19,6 +21,9 @@ namespace StardewModdingAPI.Framework.ModLoading DetectedSaveSerialiser, /// <summary>The instruction is compatible, but uses the <c>dynamic</c> keyword which won't work on Linux/Mac.</summary> - DetectedDynamic + DetectedDynamic, + + /// <summary>The instruction is compatible, but references <see cref="SpecialisedEvents.InvokeUnvalidatedUpdateTick"/> which may impact stability.</summary> + DetectedUnvalidatedUpdateTick } } diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index f080f3c5..73c87118 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -229,6 +229,7 @@ namespace StardewModdingAPI.Framework if (SGame._newDayTask != null) { base.Update(gameTime); + SpecialisedEvents.InvokeUnvalidatedUpdateTick(this.Monitor); return; } @@ -236,6 +237,7 @@ namespace StardewModdingAPI.Framework if (Game1.gameMode == Game1.loadingMode) { base.Update(gameTime); + SpecialisedEvents.InvokeUnvalidatedUpdateTick(this.Monitor); return; } @@ -267,6 +269,7 @@ namespace StardewModdingAPI.Framework // suppress non-save events base.Update(gameTime); + SpecialisedEvents.InvokeUnvalidatedUpdateTick(this.Monitor); return; } if (this.IsBetweenCreateEvents) @@ -289,9 +292,7 @@ namespace StardewModdingAPI.Framework ** Game loaded events *********/ if (this.FirstUpdate) - { GameEvents.InvokeInitialize(this.Monitor); - } /********* ** Locale changed events @@ -556,6 +557,7 @@ namespace StardewModdingAPI.Framework /********* ** Update events *********/ + SpecialisedEvents.InvokeUnvalidatedUpdateTick(this.Monitor); if (this.FirstUpdate) { this.FirstUpdate = false; diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index f285764c..5bb461c1 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -74,6 +74,7 @@ namespace StardewModdingAPI.Metadata new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerialiser), new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.farmerSerializer), InstructionHandleResult.DetectedSaveSerialiser), new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.locationSerializer), InstructionHandleResult.DetectedSaveSerialiser), + new EventFinder(typeof(SpecialisedEvents).FullName, nameof(SpecialisedEvents.UnvalidatedUpdateTick), InstructionHandleResult.DetectedUnvalidatedUpdateTick), /**** ** rewrite CIL to fix incompatible code diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 7cf62a91..562da60d 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -85,6 +85,7 @@ <Compile Include="..\..\build\GlobalAssemblyInfo.cs"> <Link>Properties\GlobalAssemblyInfo.cs</Link> </Compile> + <Compile Include="Events\SpecialisedEvents.cs" /> <Compile Include="Framework\ContentPack.cs" /> <Compile Include="Framework\Content\ContentCache.cs" /> <Compile Include="Framework\Input\InputState.cs" /> @@ -284,4 +285,4 @@ </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\build\common.targets" /> -</Project> +</Project>
\ No newline at end of file |