using Harmony.ILCopying; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; namespace Harmony { public static class PatchFunctions { public static void AddPrefix(PatchInfo patchInfo, string owner, HarmonyMethod info) { if (info == null || info.method == null) return; var priority = info.prioritiy == -1 ? Priority.Normal : info.prioritiy; var before = info.before ?? new string[0]; var after = info.after ?? new string[0]; patchInfo.AddPrefix(info.method, owner, priority, before, after); } public static void RemovePrefix(PatchInfo patchInfo, string owner) { patchInfo.RemovePrefix(owner); } public static void AddPostfix(PatchInfo patchInfo, string owner, HarmonyMethod info) { if (info == null || info.method == null) return; var priority = info.prioritiy == -1 ? Priority.Normal : info.prioritiy; var before = info.before ?? new string[0]; var after = info.after ?? new string[0]; patchInfo.AddPostfix(info.method, owner, priority, before, after); } public static void RemovePostfix(PatchInfo patchInfo, string owner) { patchInfo.RemovePostfix(owner); } public static void AddTranspiler(PatchInfo patchInfo, string owner, HarmonyMethod info) { if (info == null || info.method == null) return; var priority = info.prioritiy == -1 ? Priority.Normal : info.prioritiy; var before = info.before ?? new string[0]; var after = info.after ?? new string[0]; patchInfo.AddTranspiler(info.method, owner, priority, before, after); } public static void RemoveTranspiler(PatchInfo patchInfo, string owner) { patchInfo.RemoveTranspiler(owner); } public static void RemovePatch(PatchInfo patchInfo, MethodInfo patch) { patchInfo.RemovePatch(patch); } // pass in a generator that will create local variables for the returned instructions // public static List GetInstructions(ILGenerator generator, MethodBase method) { return MethodBodyReader.GetInstructions(generator, method); } public static List GetSortedPatchMethods(MethodBase original, Patch[] patches) { return patches .Where(p => p.patch != null) .OrderBy(p => p) .Select(p => p.GetMethod(original)) .ToList(); } public 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 replacement = MethodPatcher.CreatePatchedMethod(original, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers); 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; } } }