diff --git a/Celeste.Mod.mm/Mod/Helpers/LegacyMonoMod/Misc.cs b/Celeste.Mod.mm/Mod/Helpers/LegacyMonoMod/Misc.cs index f501e89a5..9afa055ea 100644 --- a/Celeste.Mod.mm/Mod/Helpers/LegacyMonoMod/Misc.cs +++ b/Celeste.Mod.mm/Mod/Helpers/LegacyMonoMod/Misc.cs @@ -1,3 +1,4 @@ +using Mono.Cecil; using Mono.Cecil.Cil; using MonoMod; using MonoMod.Cil; @@ -24,13 +25,8 @@ public static void Uninitialize() { } public static class ILShims { - [RelinkLegacyMonoMod("Mono.Cecil.Cil.Instruction MonoMod.Cil.ILLabel::Target")] - public static Instruction ILLabel_GetTarget(ILLabel label) => label.Target; // This previously used to be a field - - [RelinkLegacyMonoMod("System.Int32 MonoMod.Cil.ILCursor::AddReference()")] + //Relinking is done using a MonoModder hackfix because the methods are generic ._. public static int ILCursor_AddReference(ILCursor cursor, T t) => cursor.AddReference(in t); // Reorg expects an in-argument - - [RelinkLegacyMonoMod("System.Int32 MonoMod.Cil.ILCursor::EmitReference()")] public static int ILCursor_EmitReference(ILCursor cursor, T t) => cursor.EmitReference(in t); // Reorg expects an in-argument } @@ -114,4 +110,44 @@ public static void ReportMonoModCrime(string descr, Assembly perpetrator) { } } +} + +namespace MonoMod { + partial class MonoModRules { + private static void SetupLegacyMonoModPatcherHackfixes(MonoModder modder) { + // Dear MonoMod.Patcher, + // What the f*ck is this supposed to be!?!?!? + // Sincerely, me :) + // (yes this tells MonoMod to relink ILLabel::Target to ILLabel::Target, and yes this is required) + modder.RelinkMap["Mono.Cecil.Cil.Instruction MonoMod.Cil.ILLabel::Target"] = new RelinkMapEntry("MonoMod.Cil.ILLabel", "Target"); + + OnPostProcessMethod += static (modder, method) => { + if (!method.HasBody) + return; + + // We have to do our own relinking because who the heck would ever want to relink a generic method??????? + TypeDefinition ilShimsType = RulesModule.GetType("Celeste.Mod.Helpers.LegacyMonoMod.ILShims"); + foreach (Instruction instr in method.Body.Instructions) { + if (!(instr.Operand is MethodReference mref)) + continue; + + // Check if this is the correct method + if (!mref.HasThis || !(mref.IsGenericInstance || mref.HasGenericParameters) || mref.Parameters.Count != 1) + continue; + + if (mref.DeclaringType.FullName != "MonoMod.Cil.ILCursor") + continue; + + if (mref.Name != "AddReference" && mref.Name != "EmitReference") + continue; + + if (mref.Parameters[0].ParameterType.IsByReference) + continue; + + // Relink the reference + instr.Operand = modder.Module.ImportReference(ilShimsType.FindMethod($"ILCursor_{mref.Name}")); + } + }; + } + } } \ No newline at end of file diff --git a/Celeste.Mod.mm/MonoModRules.Utils.cs b/Celeste.Mod.mm/MonoModRules.Utils.cs index 42cd374b3..75f1792a1 100644 --- a/Celeste.Mod.mm/MonoModRules.Utils.cs +++ b/Celeste.Mod.mm/MonoModRules.Utils.cs @@ -107,6 +107,9 @@ public static void SetupLegacyMonoModRelinking(MonoModder modder) { // Replace assembly references which changed ReplaceAssemblyRefs(modder, static asm => asm.Name.Equals("MonoMod"), GetRulesAssemblyRef("MonoMod.Patcher")); + // Setup MonoMod.Patcher hackfixes (please just let it be rewritten already I have suffered enough ._.) + SetupLegacyMonoModPatcherHackfixes(modder); + // Convert all RelinkLegacyMonoMod attributes to MonoModLinkFrom attributes foreach (TypeDefinition type in RulesModule.Types) SetupLegacyMonoModRelinking(modder, type); diff --git a/Celeste.Mod.mm/MonoModRules.cs b/Celeste.Mod.mm/MonoModRules.cs index d8689055a..915442432 100644 --- a/Celeste.Mod.mm/MonoModRules.cs +++ b/Celeste.Mod.mm/MonoModRules.cs @@ -119,15 +119,21 @@ private static void PostProcessType(MonoModder modder, TypeDefinition type) { if (type.IsCompilerGeneratedEnumerator()) FixEnumeratorDecompile(type); - // Fix short-long opcodes - foreach (MethodDefinition method in type.Methods) + foreach (MethodDefinition method in type.Methods) { + // Run method processors + OnPostProcessMethod?.Invoke(modder, method); + + // Fix short-long opcodes method.FixShortLongOps(); + } // Post-process nested types foreach (TypeDefinition nested in type.NestedTypes) PostProcessType(modder, nested); } + private static event Action OnPostProcessMethod; + #region Commmon Helper Methods public static AssemblyName GetRulesAssemblyRef(string name) => Assembly.GetExecutingAssembly().GetReferencedAssemblies().First(asm => asm.Name.Equals(name));