summaryrefslogtreecommitdiff
path: root/src/StardewModdingAPI/Framework
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <github@jplamondonw.com>2017-03-14 20:48:02 -0400
committerJesse Plamondon-Willard <github@jplamondonw.com>2017-03-14 20:48:02 -0400
commit104aa314127bd816d5dbcac8c57ecb84b12f20d1 (patch)
tree5aae5fe3442a84c92d2e25688bedf52682f73ba7 /src/StardewModdingAPI/Framework
parent33df1e8c94aef9cb5517524cde1edbef0cefaf9f (diff)
downloadSMAPI-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.cs20
-rw-r--r--src/StardewModdingAPI/Framework/ModRegistry.cs20
-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.cs12
-rw-r--r--src/StardewModdingAPI/Framework/Models/SConfig.cs4
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; }
}
}