internal static void ReversePatch(MethodInfo standin, MethodBase original, string instanceID, MethodInfo transpiler) { var emptyFixes = new List <MethodInfo>(); var transpilers = new List <MethodInfo>(); if (transpiler != null) { transpilers.Add(transpiler); } var replacement = MethodPatcher.CreatePatchedMethod(standin, original, instanceID, emptyFixes, emptyFixes, transpilers, emptyFixes); if (replacement == null) { throw new MissingMethodException("Cannot create dynamic replacement for " + standin.FullDescription()); } var errorString = Memory.DetourMethod(standin, replacement); if (errorString != null) { throw new FormatException("Method " + standin.FullDescription() + " cannot be patched. Reason: " + errorString); } PatchTools.RememberObject(standin, replacement); }
internal static List <CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers) { if (generator == null) { throw new ArgumentNullException(nameof(generator)); } if (method == null) { throw new ArgumentNullException(nameof(method)); } var originalVariables = MethodPatcher.DeclareLocalVariables(generator, method); var useStructReturnBuffer = StructReturnBuffer.NeedsFix(method); var copier = new MethodCopier(method, generator, originalVariables); copier.SetArgumentShift(useStructReturnBuffer); var info = Harmony.GetPatchInfo(method); if (info != null) { var sortedTranspilers = PatchFunctions.GetSortedPatchMethods(method, info.Transpilers.ToArray(), false); for (var i = 0; i < maxTranspilers && i < sortedTranspilers.Count; i++) { copier.AddTranspiler(sortedTranspilers[i]); } } return(copier.Finalize(null, null, out var _)); }
/// <summary>Creates new dynamic method with the latest patches and detours the original method</summary> /// <param name="original">The original method</param> /// <param name="patchInfo">Information describing the patches</param> /// <param name="instanceID">Harmony ID</param> /// <returns>The newly created dynamic method</returns> /// internal static DynamicMethod UpdateWrapper(MethodBase original, PatchInfo patchInfo, string instanceID) { var sortedPrefixes = GetSortedPatchMethods(original, patchInfo.prefixes); var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes); var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers); var sortedFinalizers = GetSortedPatchMethods(original, patchInfo.finalizers); var replacement = MethodPatcher.CreatePatchedMethod(original, null, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers); if (replacement == null) { throw new MissingMethodException("Cannot create dynamic replacement for " + original.FullDescription()); } var errorString = Memory.DetourMethod(original, replacement); if (errorString != null) { throw new FormatException("Method " + original.FullDescription() + " cannot be patched. Reason: " + errorString); } PatchTools.RememberObject(original, replacement); // no gc for new value + release old value to gc return(replacement); }
/// <summary>Creates new replacement method with the latest patches and detours the original method</summary> /// <param name="original">The original method</param> /// <param name="patchInfo">Information describing the patches</param> /// <returns>The newly created replacement method</returns> /// internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo) { var debug = patchInfo.Debugging || Harmony.DEBUG; var sortedPrefixes = GetSortedPatchMethods(original, patchInfo.prefixes, debug); var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes, debug); var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers, debug); var sortedFinalizers = GetSortedPatchMethods(original, patchInfo.finalizers, debug); var patcher = new MethodPatcher(original, null, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers, debug); var replacement = patcher.CreateReplacement(out var finalInstructions); if (replacement == null) { throw new MissingMethodException($"Cannot create replacement for {original.FullDescription()}"); } try { Memory.DetourMethodAndPersist(original, replacement); } catch (Exception ex) { throw HarmonyException.Create(ex, finalInstructions); } return(replacement); }
internal static List <CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers) { if (generator == null) { throw new ArgumentNullException(nameof(generator)); } if (method == null) { throw new ArgumentNullException(nameof(method)); } var originalVariables = MethodPatcher.DeclareLocalVariables(generator, method); var useStructReturnBuffer = StructReturnBuffer.NeedsFix(method); var copier = new MethodCopier(method, generator, originalVariables); copier.SetArgumentShift(useStructReturnBuffer); var info = Harmony.GetPatchInfo(method); if (info != null) { var sortedTranspilers = PatchFunctions.GetSortedPatchMethods(method, info.Transpilers.ToArray(), false); for (var i = 0; i < maxTranspilers && i < sortedTranspilers.Count; i++) { copier.AddTranspiler(sortedTranspilers[i]); } } var endLabels = new List <Label>(); var emitter = new Emitter(generator, false); copier.Finalize(emitter, endLabels, out var hasReturnCode); return(emitter.GetInstructions().OrderBy(pair => pair.Key).Select(pair => pair.Value).ToList()); }
/// <summary>Returns the methods unmodified list of CodeInstructions</summary> /// <param name="original">The original method</param> /// <param name="generator">A new generator that now contains all local variables and labels contained in the result</param> /// <returns>A list containing all the original CodeInstructions</returns> public static List <CodeInstruction> GetOriginalInstructions(MethodBase original, out ILGenerator generator) { var patch = MethodPatcher.CreateDynamicMethod(original, $"_Copy{Guid.NewGuid()}"); generator = patch.GetILGenerator(); var reader = MethodBodyReader.GetInstructions(generator, original); return(reader.Select(ins => ins.GetCodeInstruction()).ToList()); }
internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler) { if (standin == null) { throw new ArgumentNullException(nameof(standin)); } if (standin.method == null) { throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}"); } var debug = (standin.debug ?? false) || Harmony.DEBUG; var transpilers = new List <MethodInfo>(); if (standin.reversePatchType == HarmonyReversePatchType.Snapshot) { var info = Harmony.GetPatchInfo(original); transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray(), debug)); } if (postTranspiler != null) { transpilers.Add(postTranspiler); } var empty = new List <MethodInfo>(); var patcher = new MethodPatcher(standin.method, original, empty, empty, transpilers, empty, debug); var replacement = patcher.CreateReplacement(out var finalInstructions); if (replacement == null) { throw new MissingMethodException($"Cannot create replacement for {standin.method.FullDescription()}"); } try { var errorString = Memory.DetourMethod(standin.method, replacement); if (errorString != null) { throw new FormatException($"Method {standin.method.FullDescription()} cannot be patched. Reason: {errorString}"); } } catch (Exception ex) { throw HarmonyException.Create(ex, finalInstructions); } PatchTools.RememberObject(standin.method, replacement); return(replacement); }
/// <summary>Creates new dynamic method with the latest patches and detours the original method</summary> /// <param name="original">The original method</param> /// <param name="patchInfo">Information describing the patches</param> /// <param name="instanceID">Harmony ID</param> /// <returns>The newly created dynamic method</returns> /// internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo, string instanceID) { var sortedPrefixes = GetSortedPatchMethods(original, patchInfo.prefixes); var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes); var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers); var sortedFinalizers = GetSortedPatchMethods(original, patchInfo.finalizers); var replacement = MethodPatcher.CreatePatchedMethod(original, null, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers); if (replacement == null) { throw new MissingMethodException($"Cannot create dynamic replacement for {original.FullDescription()}"); } Memory.DetourMethodAndPersist(original, replacement); return(replacement); }
internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, Harmony instance, MethodInfo postTranspiler) { if (standin == null) { throw new ArgumentNullException(nameof(standin)); } if (standin.method == null) { throw new ArgumentNullException($"{nameof(standin)}.{nameof(standin.method)}"); } var transpilers = new List <MethodInfo>(); if (standin.reversePatchType == HarmonyReversePatchType.Snapshot) { var info = Harmony.GetPatchInfo(original); transpilers.AddRange(GetSortedPatchMethods(original, info.Transpilers.ToArray())); } if (postTranspiler != null) { transpilers.Add(postTranspiler); } var empty = new List <MethodInfo>(); var replacement = MethodPatcher.CreatePatchedMethod(standin.method, original, instance.Id, empty, empty, transpilers, empty); if (replacement == null) { throw new MissingMethodException($"Cannot create dynamic replacement for {standin.method.FullDescription()}"); } var errorString = Memory.DetourMethod(standin.method, replacement); if (errorString != null) { throw new FormatException($"Method {standin.method.FullDescription()} cannot be patched. Reason: {errorString}"); } PatchTools.RememberObject(standin.method, replacement); return(replacement); }
internal static void UpdateRecompiledMethod(MethodBase original, IntPtr codeStart, PatchInfo patchInfo) { try { var sortedPrefixes = GetSortedPatchMethods(original, patchInfo.prefixes, false); var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes, false); var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers, false); var sortedFinalizers = GetSortedPatchMethods(original, patchInfo.finalizers, false); var patcher = new MethodPatcher(original, null, sortedPrefixes, sortedPostfixes, sortedTranspilers, sortedFinalizers, false); var replacement = patcher.CreateReplacement(out var finalInstructions); if (replacement is null) { throw new MissingMethodException($"Cannot create replacement for {original.FullDescription()}"); } Memory.DetourCompiledMethod(codeStart, replacement); } catch { } }