diff options
author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-03-14 20:48:02 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-03-14 20:48:02 -0400 |
commit | 104aa314127bd816d5dbcac8c57ecb84b12f20d1 (patch) | |
tree | 5aae5fe3442a84c92d2e25688bedf52682f73ba7 /src/StardewModdingAPI/Framework | |
parent | 33df1e8c94aef9cb5517524cde1edbef0cefaf9f (diff) | |
download | SMAPI-104aa314127bd816d5dbcac8c57ecb84b12f20d1.tar.gz SMAPI-104aa314127bd816d5dbcac8c57ecb84b12f20d1.tar.bz2 SMAPI-104aa314127bd816d5dbcac8c57ecb84b12f20d1.zip |
let players override SMAPI incompatible-code detection if needed
Diffstat (limited to 'src/StardewModdingAPI/Framework')
-rw-r--r-- | src/StardewModdingAPI/Framework/AssemblyLoader.cs | 20 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/ModRegistry.cs | 20 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/Models/ModCompatibility.cs (renamed from src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs) | 10 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/Models/ModCompatibilityType.cs | 12 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/Models/SConfig.cs | 4 |
5 files changed, 41 insertions, 25 deletions
diff --git a/src/StardewModdingAPI/Framework/AssemblyLoader.cs b/src/StardewModdingAPI/Framework/AssemblyLoader.cs index bc56de01..c7ad3da4 100644 --- a/src/StardewModdingAPI/Framework/AssemblyLoader.cs +++ b/src/StardewModdingAPI/Framework/AssemblyLoader.cs @@ -54,9 +54,10 @@ namespace StardewModdingAPI.Framework /// <summary>Preprocess and load an assembly.</summary> /// <param name="assemblyPath">The assembly file path.</param> + /// <param name="assumeCompatible">Assume the mod is compatible, even if incompatible code is detected.</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) + public Assembly Load(string assemblyPath, bool assumeCompatible) { // get referenced local assemblies AssemblyParseResult[] assemblies; @@ -73,7 +74,7 @@ namespace StardewModdingAPI.Framework Assembly lastAssembly = null; foreach (AssemblyParseResult assembly in assemblies) { - bool changed = this.RewriteAssembly(assembly.Definition); + bool changed = this.RewriteAssembly(assembly.Definition, assumeCompatible); if (changed) { this.Monitor.Log($"Loading {assembly.File.Name} (rewritten in memory)...", LogLevel.Trace); @@ -159,12 +160,13 @@ namespace StardewModdingAPI.Framework ****/ /// <summary>Rewrite the types referenced by an assembly.</summary> /// <param name="assembly">The assembly to rewrite.</param> + /// <param name="assumeCompatible">Assume the mod is compatible, even if incompatible code is detected.</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) + private bool RewriteAssembly(AssemblyDefinition assembly, bool assumeCompatible) { ModuleDefinition module = assembly.MainModule; - HashSet<string> loggedRewrites = new HashSet<string>(); + HashSet<string> loggedMessages = new HashSet<string>(); // swap assembly references if needed (e.g. XNA => MonoGame) bool platformChanged = false; @@ -173,7 +175,7 @@ namespace StardewModdingAPI.Framework // remove old assembly reference if (this.AssemblyMap.RemoveNames.Any(name => module.AssemblyReferences[i].Name == name)) { - this.LogOnce(this.Monitor, loggedRewrites, $"Rewriting {assembly.Name.Name} for OS..."); + this.LogOnce(this.Monitor, loggedMessages, $"Rewriting {assembly.Name.Name} for OS..."); platformChanged = true; module.AssemblyReferences.RemoveAt(i); i--; @@ -203,13 +205,17 @@ namespace StardewModdingAPI.Framework // throw exception if instruction is incompatible but can't be rewritten IInstructionFinder finder = finders.FirstOrDefault(p => p.IsMatch(instruction, platformChanged)); if (finder != null) - throw new IncompatibleInstructionException(finder.NounPhrase, $"Found an incompatible CIL instruction ({finder.NounPhrase}) while loading assembly {assembly.Name.Name}."); + { + 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 IInstructionRewriter rewriter = rewriters.FirstOrDefault(p => p.IsMatch(instruction, platformChanged)); if (rewriter != null) { - this.LogOnce(this.Monitor, loggedRewrites, $"Rewriting {assembly.Name.Name} to fix {rewriter.NounPhrase}..."); + this.LogOnce(this.Monitor, loggedMessages, $"Rewriting {assembly.Name.Name} to fix {rewriter.NounPhrase}..."); rewriter.Rewrite(module, cil, instruction, this.AssemblyMap); anyRewritten = true; } diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs index 233deb3c..f015b7ba 100644 --- a/src/StardewModdingAPI/Framework/ModRegistry.cs +++ b/src/StardewModdingAPI/Framework/ModRegistry.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; -using System.Text.RegularExpressions; using StardewModdingAPI.Framework.Models; namespace StardewModdingAPI.Framework @@ -20,18 +19,18 @@ namespace StardewModdingAPI.Framework /// <summary>The friendly mod names treated as deprecation warning sources (assembly full name => mod name).</summary> private readonly IDictionary<string, string> ModNamesByAssembly = new Dictionary<string, string>(); - /// <summary>The mod versions which should be disabled due to incompatibility.</summary> - private readonly IncompatibleMod[] IncompatibleMods; + /// <summary>Metadata about mods that SMAPI should assume is compatible or broken, regardless of whether it detects incompatible code.</summary> + private readonly ModCompatibility[] CompatibilityRecords; /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> - /// <param name="incompatibleMods">The mod versions which should be disabled due to incompatibility.</param> - public ModRegistry(IEnumerable<IncompatibleMod> incompatibleMods) + /// <param name="compatibilityRecords">Metadata about mods that SMAPI should assume is compatible or broken, regardless of whether it detects incompatible code.</param> + public ModRegistry(IEnumerable<ModCompatibility> compatibilityRecords) { - this.IncompatibleMods = incompatibleMods.ToArray(); + this.CompatibilityRecords = compatibilityRecords.ToArray(); } @@ -127,21 +126,20 @@ namespace StardewModdingAPI.Framework return null; } - /// <summary>Get a record indicating why a mod is incompatible (if applicable).</summary> + /// <summary>Get metadata that indicates whether SMAPI should assume the mod is compatible or broken, regardless of whether it detects incompatible code.</summary> /// <param name="manifest">The mod manifest.</param> /// <returns>Returns the incompatibility record if applicable, else <c>null</c>.</returns> - internal IncompatibleMod GetIncompatibilityRecord(IManifest manifest) + internal ModCompatibility GetCompatibilityRecord(IManifest manifest) { string key = !string.IsNullOrWhiteSpace(manifest.UniqueID) ? manifest.UniqueID : manifest.EntryDll; return ( - from mod in this.IncompatibleMods + from mod in this.CompatibilityRecords where mod.ID == key && (mod.LowerSemanticVersion == null || !manifest.Version.IsOlderThan(mod.LowerSemanticVersion)) && !manifest.Version.IsNewerThan(mod.UpperSemanticVersion) - && (string.IsNullOrWhiteSpace(mod.ForceCompatibleVersion) || !Regex.IsMatch(manifest.Version.ToString(), mod.ForceCompatibleVersion, RegexOptions.IgnoreCase)) select mod ).FirstOrDefault(); } } -}
\ No newline at end of file +} diff --git a/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs index 29e18ddb..1e71dae0 100644 --- a/src/StardewModdingAPI/Framework/Models/IncompatibleMod.cs +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibility.cs @@ -3,8 +3,8 @@ using Newtonsoft.Json; namespace StardewModdingAPI.Framework.Models { - /// <summary>Contains abstract metadata about an incompatible mod.</summary> - internal class IncompatibleMod + /// <summary>Metadata about a mod version that SMAPI should assume is compatible or broken, regardless of whether it detects incompatible code.</summary> + internal class ModCompatibility { /********* ** Accessors @@ -30,13 +30,13 @@ namespace StardewModdingAPI.Framework.Models /// <summary>The URL the user can check for an unofficial updated version.</summary> public string UnofficialUpdateUrl { get; set; } - /// <summary>A regular expression matching version strings to consider compatible, even if they technically precede <see cref="UpperVersion"/>.</summary> - public string ForceCompatibleVersion { get; set; } - /// <summary>The reason phrase to show in the warning, or <c>null</c> to use the default value.</summary> /// <example>"this version is incompatible with the latest version of the game"</example> public string ReasonPhrase { get; set; } + /// <summary>Indicates how SMAPI should consider the mod.</summary> + public ModCompatibilityType Compatibility { get; set; } + /**** ** Injected diff --git a/src/StardewModdingAPI/Framework/Models/ModCompatibilityType.cs b/src/StardewModdingAPI/Framework/Models/ModCompatibilityType.cs new file mode 100644 index 00000000..35edec5e --- /dev/null +++ b/src/StardewModdingAPI/Framework/Models/ModCompatibilityType.cs @@ -0,0 +1,12 @@ +namespace StardewModdingAPI.Framework.Models +{ + /// <summary>Indicates how SMAPI should consider a mod.</summary> + internal enum ModCompatibilityType + { + /// <summary>Assume the mod is not compatible, even if SMAPI doesn't detect any incompatible code.</summary> + AssumeBroken = 0, + + /// <summary>Assume the mod is compatible, even if SMAPI detects incompatible code.</summary> + AssumeCompatible = 1 + } +} diff --git a/src/StardewModdingAPI/Framework/Models/SConfig.cs b/src/StardewModdingAPI/Framework/Models/SConfig.cs index 558da82a..0de96297 100644 --- a/src/StardewModdingAPI/Framework/Models/SConfig.cs +++ b/src/StardewModdingAPI/Framework/Models/SConfig.cs @@ -12,7 +12,7 @@ /// <summary>Whether to check if a newer version of SMAPI is available on startup.</summary> public bool CheckForUpdates { get; set; } = true; - /// <summary>A list of mod versions which should be considered incompatible.</summary> - public IncompatibleMod[] IncompatibleMods { get; set; } + /// <summary>A list of mod versions which should be considered compatible or incompatible regardless of whether SMAPI detects incompatible code.</summary> + public ModCompatibility[] ModCompatibility { get; set; } } } |