summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI
diff options
context:
space:
mode:
Diffstat (limited to 'src/StardewModdingAPI')
-rw-r--r--src/StardewModdingAPI/Constants.cs23
-rw-r--r--src/StardewModdingAPI/Framework/AssemblyLoader.cs33
-rw-r--r--src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs27
-rw-r--r--src/StardewModdingAPI/Program.cs1
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj1
5 files changed, 27 insertions, 58 deletions
diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs
index 52be6c05..de0eab57 100644
--- a/src/StardewModdingAPI/Constants.cs
+++ b/src/StardewModdingAPI/Constants.cs
@@ -137,12 +137,15 @@ namespace StardewModdingAPI
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences, targetAssemblies);
}
- /// <summary>Get finders which match incompatible CIL instructions in mod assemblies.</summary>
- internal static IEnumerable<IInstructionFinder> GetIncompatibilityFinders()
+ /// <summary>Get rewriters which detect or fix incompatible CIL instructions in mod assemblies.</summary>
+ internal static IEnumerable<IInstructionRewriter> GetRewriters()
{
- return new IInstructionFinder[]
+ return new IInstructionRewriter[]
{
- // changes in Stardew Valley 1.2 (that don't have rewriters)
+ /****
+ ** Finders throw an exception when incompatible code is found.
+ ****/
+ // changes in Stardew Valley 1.2 (with no rewriters)
new FieldFinder("StardewValley.Item", "set_Name"),
// APIs removed in SMAPI 1.9
@@ -161,15 +164,11 @@ namespace StardewModdingAPI
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPostRenderHudEventNoCheck"),
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPostRenderGuiEventNoCheck"),
new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPreRenderHudEventNoCheck"),
- new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPreRenderGuiEventNoCheck")
- };
- }
+ new EventFinder("StardewModdingAPI.Events.GraphicsEvents", "OnPreRenderGuiEventNoCheck"),
- /// <summary>Get rewriters which fix incompatible CIL instructions in mod assemblies.</summary>
- internal static IEnumerable<IInstructionRewriter> GetRewriters()
- {
- return new IInstructionRewriter[]
- {
+ /****
+ ** Rewriters change CIL as needed to fix incompatible code
+ ****/
// crossplatform
new MethodParentRewriter(typeof(SpriteBatch), typeof(SpriteBatchWrapper), onlyIfPlatformChanged: true),
diff --git a/src/StardewModdingAPI/Framework/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/AssemblyLoader.cs
index aee0bbb3..5d00c525 100644
--- a/src/StardewModdingAPI/Framework/AssemblyLoader.cs
+++ b/src/StardewModdingAPI/Framework/AssemblyLoader.cs
@@ -193,33 +193,30 @@ namespace StardewModdingAPI.Framework
this.ChangeTypeScope(type);
}
- // find incompatible instructions
+ // find (and optionally rewrite) incompatible instructions
bool anyRewritten = false;
- IInstructionFinder[] finders = Constants.GetIncompatibilityFinders().ToArray();
IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray();
foreach (MethodDefinition method in this.GetMethods(module))
{
ILProcessor cil = method.Body.GetILProcessor();
foreach (Instruction instruction in cil.Body.Instructions.ToArray())
{
- // throw exception if instruction is incompatible but can't be rewritten
- IInstructionFinder finder = finders.FirstOrDefault(p => p.IsMatch(instruction, platformChanged));
- if (finder != null)
- {
- if (!assumeCompatible)
- throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}.");
- this.LogOnce(this.Monitor, loggedMessages, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}, but SMAPI is configured to allow it anyway. The mod may crash or behave unexpectedly.", LogLevel.Warn);
- }
-
- // rewrite instruction if needed
foreach (IInstructionRewriter rewriter in rewriters)
{
- if (!rewriter.IsMatch(instruction, platformChanged))
- continue;
-
- this.LogOnce(this.Monitor, loggedMessages, $"Rewriting {assembly.Name.Name} to fix {rewriter.NounPhrase}...");
- rewriter.Rewrite(module, cil, instruction, this.AssemblyMap);
- anyRewritten = true;
+ try
+ {
+ if (rewriter.Rewrite(module, cil, instruction, this.AssemblyMap, platformChanged))
+ {
+ this.LogOnce(this.Monitor, loggedMessages, $"Rewrote {assembly.Name.Name} to fix {rewriter.NounPhrase}...");
+ anyRewritten = true;
+ }
+ }
+ catch (IncompatibleInstructionException)
+ {
+ if (!assumeCompatible)
+ throw new IncompatibleInstructionException(rewriter.NounPhrase, $"Found an incompatible CIL instruction ({rewriter.NounPhrase}) while loading assembly {assembly.Name.Name}.");
+ this.LogOnce(this.Monitor, loggedMessages, $"Found an incompatible CIL instruction ({rewriter.NounPhrase}) while loading assembly {assembly.Name.Name}, but SMAPI is configured to allow it anyway. The mod may crash or behave unexpectedly.", LogLevel.Warn);
+ }
}
}
}
diff --git a/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs b/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs
deleted file mode 100644
index affe2cb3..00000000
--- a/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-
-namespace StardewModdingAPI.Framework
-{
- /// <summary>An exception raised when an incompatible instruction is found while loading a mod assembly.</summary>
- internal class IncompatibleInstructionException : Exception
- {
- /*********
- ** Accessors
- *********/
- /// <summary>A brief noun phrase which describes the incompatible instruction that was found.</summary>
- public string NounPhrase { get; }
-
-
- /*********
- ** Public methods
- *********/
- /// <summary>Construct an instance.</summary>
- /// <param name="nounPhrase">A brief noun phrase which describes the incompatible instruction that was found.</param>
- /// <param name="message">A message which describes the error.</param>
- public IncompatibleInstructionException(string nounPhrase, string message)
- : base(message)
- {
- this.NounPhrase = nounPhrase;
- }
- }
-}
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index ac646b1f..25605148 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -12,6 +12,7 @@ using System.Windows.Forms;
#endif
using Microsoft.Xna.Framework.Graphics;
using Newtonsoft.Json;
+using StardewModdingAPI.AssemblyRewriters;
using StardewModdingAPI.Events;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Logging;
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj
index 091b3d90..bcd0c390 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.csproj
+++ b/src/StardewModdingAPI/StardewModdingAPI.csproj
@@ -150,7 +150,6 @@
<Compile Include="Framework\Content\ContentEventHelper.cs" />
<Compile Include="Framework\Content\ContentEventHelperForDictionary.cs" />
<Compile Include="Framework\Content\ContentEventHelperForImage.cs" />
- <Compile Include="Framework\IncompatibleInstructionException.cs" />
<Compile Include="Framework\Logging\ConsoleInterceptionManager.cs" />
<Compile Include="Framework\Logging\InterceptingTextWriter.cs" />
<Compile Include="Framework\CommandHelper.cs" />