summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/release-notes.md3
-rw-r--r--src/SMAPI/Events/SpecialisedEvents.cs26
-rw-r--r--src/SMAPI/Framework/ModLoading/AssemblyLoader.cs5
-rw-r--r--src/SMAPI/Framework/ModLoading/InstructionHandleResult.cs7
-rw-r--r--src/SMAPI/Framework/SGame.cs6
-rw-r--r--src/SMAPI/Metadata/InstructionMetadata.cs1
-rw-r--r--src/SMAPI/StardewModdingAPI.csproj3
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