From 85ed48809032fdbb8461ce4c34acfbe06f68652b Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 26 Mar 2017 19:01:35 -0400 Subject: merge CIL finders & rewriters into one interface (#254) --- src/StardewModdingAPI/Constants.cs | 23 ++++++++------- src/StardewModdingAPI/Framework/AssemblyLoader.cs | 33 ++++++++++------------ .../Framework/IncompatibleInstructionException.cs | 27 ------------------ src/StardewModdingAPI/Program.cs | 1 + src/StardewModdingAPI/StardewModdingAPI.csproj | 1 - 5 files changed, 27 insertions(+), 58 deletions(-) delete mode 100644 src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs (limited to 'src/StardewModdingAPI') 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); } - /// Get finders which match incompatible CIL instructions in mod assemblies. - internal static IEnumerable GetIncompatibilityFinders() + /// Get rewriters which detect or fix incompatible CIL instructions in mod assemblies. + internal static IEnumerable 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"), - /// Get rewriters which fix incompatible CIL instructions in mod assemblies. - internal static IEnumerable 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 -{ - /// An exception raised when an incompatible instruction is found while loading a mod assembly. - internal class IncompatibleInstructionException : Exception - { - /********* - ** Accessors - *********/ - /// A brief noun phrase which describes the incompatible instruction that was found. - public string NounPhrase { get; } - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// A brief noun phrase which describes the incompatible instruction that was found. - /// A message which describes the error. - 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 @@ - -- cgit