diff options
author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-03-12 01:31:15 -0500 |
---|---|---|
committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-03-12 01:31:15 -0500 |
commit | 6d2d90b7681e4e274e92742e98905ec4000486ca (patch) | |
tree | 80241918427c710303156d18f369f9b3b92717e6 | |
parent | b0fab4a0764d4cd1eb807db88e704aa401e4f716 (diff) | |
download | SMAPI-6d2d90b7681e4e274e92742e98905ec4000486ca.tar.gz SMAPI-6d2d90b7681e4e274e92742e98905ec4000486ca.tar.bz2 SMAPI-6d2d90b7681e4e274e92742e98905ec4000486ca.zip |
add logic to detect incompatible mod instructions & reject mod load (#247)
-rw-r--r-- | src/StardewModdingAPI/Constants.cs | 8 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/AssemblyLoader.cs | 18 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs | 27 | ||||
-rw-r--r-- | src/StardewModdingAPI/Program.cs | 5 | ||||
-rw-r--r-- | src/StardewModdingAPI/StardewModdingAPI.csproj | 1 |
5 files changed, 59 insertions, 0 deletions
diff --git a/src/StardewModdingAPI/Constants.cs b/src/StardewModdingAPI/Constants.cs index 66bf5842..d8149766 100644 --- a/src/StardewModdingAPI/Constants.cs +++ b/src/StardewModdingAPI/Constants.cs @@ -135,6 +135,14 @@ 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() + { + return new IInstructionFinder[] + { + }; + } + /// <summary>Get rewriters which fix incompatible CIL instructions in mod assemblies.</summary> internal static IEnumerable<IInstructionRewriter> GetRewriters() { diff --git a/src/StardewModdingAPI/Framework/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/AssemblyLoader.cs index 8af67772..dfe0d03f 100644 --- a/src/StardewModdingAPI/Framework/AssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/AssemblyLoader.cs @@ -55,6 +55,7 @@ namespace StardewModdingAPI.Framework /// <summary>Preprocess and load an assembly.</summary> /// <param name="assemblyPath">The assembly file path.</param> /// <returns>Returns the rewrite metadata for the preprocessed assembly.</returns> + /// <exception cref="IncompatibleInstructionException">An incompatible CIL instruction was found while rewriting the assembly.</exception> public Assembly Load(string assemblyPath) { // get referenced local assemblies @@ -159,6 +160,7 @@ namespace StardewModdingAPI.Framework /// <summary>Rewrite the types referenced by an assembly.</summary> /// <param name="assembly">The assembly to rewrite.</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(AssemblyDefinition assembly) { ModuleDefinition module = assembly.MainModule; @@ -189,6 +191,22 @@ namespace StardewModdingAPI.Framework this.ChangeTypeScope(type); } + // throw exception if assembly contains incompatible instructions can't be rewritten + { + IInstructionFinder[] finders = Constants.GetIncompatibilityFinders().ToArray(); + foreach (MethodDefinition method in this.GetMethods(module)) + { + foreach (Instruction instruction in method.Body.Instructions) + { + foreach (IInstructionFinder finder in finders) + { + if (finder.IsMatch(instruction, platformChanged)) + throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}."); + } + } + } + } + // rewrite incompatible instructions bool anyRewritten = false; IInstructionRewriter[] rewriters = Constants.GetRewriters().ToArray(); diff --git a/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs b/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs new file mode 100644 index 00000000..affe2cb3 --- /dev/null +++ b/src/StardewModdingAPI/Framework/IncompatibleInstructionException.cs @@ -0,0 +1,27 @@ +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 bf3c86fb..cb8cc2e5 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -453,6 +453,11 @@ namespace StardewModdingAPI { modAssembly = modAssemblyLoader.Load(assemblyPath); } + catch (IncompatibleInstructionException ex) + { + this.Monitor.Log($"{skippedPrefix} because it's not compatible with the latest version of the game (detected {ex.NounPhrase}). Please check for a newer version of the mod (you have v{manifest.Version}).", LogLevel.Error); + continue; + } catch (Exception ex) { this.Monitor.Log($"{skippedPrefix} because its DLL '{manifest.EntryDll}' couldn't be loaded.\n{ex.GetLogSummary()}", LogLevel.Error); diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index ab808948..92726ca0 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -154,6 +154,7 @@ <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" /> |