summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs')
-rw-r--r--src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs
new file mode 100644
index 00000000..29e44bfe
--- /dev/null
+++ b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs
@@ -0,0 +1,77 @@
+using System;
+using Mono.Cecil;
+using StardewModdingAPI.Framework.ModLoading.Finders;
+using StardewModdingAPI.Framework.ModLoading.Framework;
+
+namespace StardewModdingAPI.Framework.ModLoading.Rewriters
+{
+ /// <summary>Rewrites Harmony 1.x assembly references to work with Harmony 2.x.</summary>
+ internal class Harmony1AssemblyRewriter : BaseTypeReferenceRewriter
+ {
+ /*********
+ ** Fields
+ *********/
+ /// <summary>The full assembly name to which to find references.</summary>
+ private const string FromAssemblyName = "0Harmony";
+
+ /// <summary>The main Harmony type.</summary>
+ private readonly Type HarmonyType = typeof(HarmonyLib.Harmony);
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ public Harmony1AssemblyRewriter()
+ : base(new TypeAssemblyFinder(Harmony1AssemblyRewriter.FromAssemblyName, InstructionHandleResult.None), "Harmony 1.x types")
+ { }
+
+
+ /*********
+ ** Private methods
+ *********/
+ /// <summary>Change a type reference if needed.</summary>
+ /// <param name="module">The assembly module containing the instruction.</param>
+ /// <param name="type">The type to replace if it matches.</param>
+ /// <param name="set">Assign the new type reference.</param>
+ protected override bool RewriteIfNeeded(ModuleDefinition module, TypeReference type, Action<TypeReference> set)
+ {
+ bool rewritten = false;
+
+ // current type
+ if (type.Scope.Name == Harmony1AssemblyRewriter.FromAssemblyName && type.Scope is AssemblyNameReference assemblyScope && assemblyScope.Version.Major == 1)
+ {
+ Type targetType = this.GetMappedType(type);
+ set(module.ImportReference(targetType));
+ return true;
+ }
+
+ // recurse into generic arguments
+ if (type is GenericInstanceType genericType)
+ {
+ for (int i = 0; i < genericType.GenericArguments.Count; i++)
+ rewritten |= this.RewriteIfNeeded(module, genericType.GenericArguments[i], typeRef => genericType.GenericArguments[i] = typeRef);
+ }
+
+ // recurse into generic parameters (e.g. constraints)
+ for (int i = 0; i < type.GenericParameters.Count; i++)
+ rewritten |= this.RewriteIfNeeded(module, type.GenericParameters[i], typeRef => type.GenericParameters[i] = new GenericParameter(typeRef));
+
+ return rewritten;
+ }
+
+ /// <summary>Get an equivalent Harmony 2.x type.</summary>
+ /// <param name="type">The Harmony 1.x method.</param>
+ private Type GetMappedType(TypeReference type)
+ {
+ // main Harmony object
+ if (type.FullName == "Harmony.HarmonyInstance")
+ return this.HarmonyType;
+
+ // other objects
+ string fullName = type.FullName.Replace("Harmony.", "HarmonyLib.");
+ string targetName = this.HarmonyType.AssemblyQualifiedName.Replace(this.HarmonyType.FullName, fullName);
+ return Type.GetType(targetName, throwOnError: true);
+ }
+ }
+}