summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release-notes.md5
-rw-r--r--src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs19
-rw-r--r--src/StardewModdingAPI/Framework/ModLoading/InstructionHandleResult.cs5
-rw-r--r--src/StardewModdingAPI/Metadata/InstructionMetadata.cs5
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj1
5 files changed, 25 insertions, 10 deletions
diff --git a/release-notes.md b/release-notes.md
index 5e01a264..6d430c7a 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -3,8 +3,9 @@
<!--See [log](https://github.com/Pathoschild/SMAPI/compare/1.10...2.0).-->
For players:
-* The SMAPI console is now much simpler and easier to read.
-* The SMAPI console now adjusts its colors when you have a light terminal background.
+* The console is now simpler and easier to read.
+* The console now adjusts its colors when you have a light terminal background.
+* SMAPI now detects mods which may impact game stability and shows a warning in the console.
* Updated compatibility list.
For mod developers:
diff --git a/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs
index b78bf6bb..835ef631 100644
--- a/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs
+++ b/src/StardewModdingAPI/Framework/ModLoading/AssemblyLoader.cs
@@ -83,12 +83,13 @@ namespace StardewModdingAPI.Framework.ModLoading
// rewrite & load assemblies in leaf-to-root order
bool oneAssembly = assemblies.Length == 1;
Assembly lastAssembly = null;
+ HashSet<string> loggedMessages = new HashSet<string>();
foreach (AssemblyParseResult assembly in assemblies)
{
if (assembly.Status == AssemblyLoadStatus.AlreadyLoaded)
continue;
- bool changed = this.RewriteAssembly(mod, assembly.Definition, assumeCompatible, logPrefix: " ");
+ bool changed = this.RewriteAssembly(mod, assembly.Definition, assumeCompatible, loggedMessages, logPrefix: " ");
if (changed)
{
if (!oneAssembly)
@@ -178,13 +179,13 @@ namespace StardewModdingAPI.Framework.ModLoading
/// <param name="mod">The mod for which the assembly is being loaded.</param>
/// <param name="assembly">The assembly to rewrite.</param>
/// <param name="assumeCompatible">Assume the mod is compatible, even if incompatible code is detected.</param>
+ /// <param name="loggedMessages">The messages that have already been logged for this mod.</param>
/// <param name="logPrefix">A string to prefix to log messages.</param>
/// <returns>Returns whether the assembly was modified.</returns>
/// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception>
- private bool RewriteAssembly(IModMetadata mod, AssemblyDefinition assembly, bool assumeCompatible, string logPrefix)
+ private bool RewriteAssembly(IModMetadata mod, AssemblyDefinition assembly, bool assumeCompatible, HashSet<string> loggedMessages, string logPrefix)
{
ModuleDefinition module = assembly.MainModule;
- HashSet<string> loggedMessages = new HashSet<string>();
string filename = $"{assembly.Name.Name}.dll";
// swap assembly references if needed (e.g. XNA => MonoGame)
@@ -221,7 +222,7 @@ namespace StardewModdingAPI.Framework.ModLoading
foreach (IInstructionHandler handler in handlers)
{
InstructionHandleResult result = handler.Handle(mod, module, method, this.AssemblyMap, platformChanged);
- this.ProcessInstructionHandleResult(handler, result, loggedMessages, logPrefix, assumeCompatible, filename);
+ this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, assumeCompatible, filename);
if (result == InstructionHandleResult.Rewritten)
anyRewritten = true;
}
@@ -233,7 +234,7 @@ namespace StardewModdingAPI.Framework.ModLoading
foreach (IInstructionHandler handler in handlers)
{
InstructionHandleResult result = handler.Handle(mod, module, cil, instruction, this.AssemblyMap, platformChanged);
- this.ProcessInstructionHandleResult(handler, result, loggedMessages, logPrefix, assumeCompatible, filename);
+ this.ProcessInstructionHandleResult(mod, handler, result, loggedMessages, logPrefix, assumeCompatible, filename);
if (result == InstructionHandleResult.Rewritten)
anyRewritten = true;
}
@@ -244,13 +245,14 @@ namespace StardewModdingAPI.Framework.ModLoading
}
/// <summary>Process the result from an instruction handler.</summary>
+ /// <param name="mod">The mod being analysed.</param>
/// <param name="handler">The instruction handler.</param>
/// <param name="result">The result returned by the handler.</param>
/// <param name="loggedMessages">The messages already logged for the current mod.</param>
/// <param name="assumeCompatible">Assume the mod is compatible, even if incompatible code is detected.</param>
/// <param name="logPrefix">A string to prefix to log messages.</param>
/// <param name="filename">The assembly filename for log messages.</param>
- private void ProcessInstructionHandleResult(IInstructionHandler handler, InstructionHandleResult result, HashSet<string> loggedMessages, string logPrefix, bool assumeCompatible, string filename)
+ private void ProcessInstructionHandleResult(IModMetadata mod, IInstructionHandler handler, InstructionHandleResult result, HashSet<string> loggedMessages, string logPrefix, bool assumeCompatible, string filename)
{
switch (result)
{
@@ -264,6 +266,11 @@ namespace StardewModdingAPI.Framework.ModLoading
this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Found an incompatible CIL instruction ({handler.NounPhrase}) while loading assembly {filename}, but SMAPI is configured to allow it anyway. The mod may crash or behave unexpectedly.", LogLevel.Warn);
break;
+ case InstructionHandleResult.DetectedGamePatch:
+ this.Monitor.LogOnce(loggedMessages, $"{logPrefix}Detected {handler.NounPhrase} in assembly {filename}.");
+ this.Monitor.LogOnce(loggedMessages, $"{mod.DisplayName} patches the game in a way that may impact game stability (detected {handler.NounPhrase}).", LogLevel.Warn);
+ break;
+
case InstructionHandleResult.None:
break;
diff --git a/src/StardewModdingAPI/Framework/ModLoading/InstructionHandleResult.cs b/src/StardewModdingAPI/Framework/ModLoading/InstructionHandleResult.cs
index 3921e9c4..f4abb095 100644
--- a/src/StardewModdingAPI/Framework/ModLoading/InstructionHandleResult.cs
+++ b/src/StardewModdingAPI/Framework/ModLoading/InstructionHandleResult.cs
@@ -10,6 +10,9 @@ namespace StardewModdingAPI.Framework.ModLoading
Rewritten,
/// <summary>The instruction is not compatible and can't be rewritten for compatibility.</summary>
- NotCompatible
+ NotCompatible,
+
+ /// <summary>The instruction is compatible, but patches the game in a way that may impact stability.</summary>
+ DetectedGamePatch
}
}
diff --git a/src/StardewModdingAPI/Metadata/InstructionMetadata.cs b/src/StardewModdingAPI/Metadata/InstructionMetadata.cs
index fc4f112c..c53755ae 100644
--- a/src/StardewModdingAPI/Metadata/InstructionMetadata.cs
+++ b/src/StardewModdingAPI/Metadata/InstructionMetadata.cs
@@ -70,6 +70,11 @@ namespace StardewModdingAPI.Metadata
#endif
/****
+ ** detect code which may impact game stability
+ ****/
+ new TypeFinder("Harmony.HarmonyInstance", InstructionHandleResult.DetectedGamePatch),
+
+ /****
** rewrite CIL to fix incompatible code
****/
// crossplatform
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj
index 175fc3f3..8da93bf4 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.csproj
+++ b/src/StardewModdingAPI/StardewModdingAPI.csproj
@@ -110,7 +110,6 @@
<Compile Include="Framework\ContentManagerShim.cs" />
<Compile Include="Framework\Exceptions\SAssemblyLoadFailedException.cs" />
<Compile Include="Framework\ModLoading\AssemblyLoadStatus.cs" />
- <Compile Include="Framework\ModLoading\DangerousCodeWarner.cs" />
<Compile Include="Framework\Utilities\ContextHash.cs" />
<Compile Include="Metadata\CoreAssets.cs" />
<Compile Include="ContentSource.cs" />