/// <summary>Serializes a patch info</summary> /// <param name="patchInfo">The <see cref="PatchInfo"/></param> /// <returns>The serialized data</returns> /// internal static byte[] Serialize(this PatchInfo patchInfo) { #pragma warning disable XS0001 using var streamMemory = new MemoryStream(); var formatter = new BinaryFormatter(); formatter.Serialize(streamMemory, patchInfo); return(streamMemory.GetBuffer()); #pragma warning restore XS0001 }
/// <summary>Gets patch information on an original</summary> /// <param name="method">The original method/constructor</param> /// <returns>The patch information as <see cref="Patches"/></returns> /// public static Patches GetPatchInfo(MethodBase method) { PatchInfo patchInfo = method.GetPatchInfo(); if (patchInfo is null) { return(null); } return(new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers, patchInfo.finalizers, patchInfo.ilmanipulators)); }
void ProcessPatchJob(PatchJobs <MethodInfo> .Job job) { MethodInfo replacement = default; var individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, false, null, job.original); Exception exception = null; if (individualPrepareResult) { lock (PatchProcessor.locker) { try { var patchInfo = HarmonySharedState.GetPatchInfo(job.original); if (patchInfo == null) { patchInfo = new PatchInfo(); } foreach (var prefix in job.prefixes) { PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix); } foreach (var postfix in job.postfixes) { PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix); } foreach (var transpiler in job.transpilers) { PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler); } foreach (var finalizer in job.finalizers) { PatchFunctions.AddFinalizer(patchInfo, instance.Id, finalizer); } replacement = PatchFunctions.UpdateWrapper(job.original, patchInfo); HarmonySharedState.UpdatePatchInfo(job.original, patchInfo); } catch (Exception ex) { exception = ex; } } } RunMethod <HarmonyCleanup>(ref exception, job.original, exception); if (exception != null) { ReportException(exception, job.original); } job.replacement = replacement; }
/// <summary>Adds a finalizer</summary> /// <param name="patchInfo">The patch info</param> /// <param name="owner">The owner (Harmony ID)</param> /// <param name="info">The annotation info</param> /// internal static void AddFinalizer(PatchInfo patchInfo, string owner, HarmonyMethod info) { if (info == null || info.method == null) { return; } var priority = info.priority == -1 ? Priority.Normal : info.priority; var before = info.before ?? new string[0]; var after = info.after ?? new string[0]; patchInfo.AddFinalizer(info.method, owner, priority, before, after); }
/// <summary>Adds a postfix</summary> /// <param name="patchInfo">The patch info</param> /// <param name="owner">The owner (Harmony ID)</param> /// <param name="info">The annotation info</param> /// internal static void AddPostfix(PatchInfo patchInfo, string owner, HarmonyMethod info) { if (info == null || info.method == null) { return; } var priority = info.priority == -1 ? Priority.Normal : info.priority; var before = info.before ?? new string[0]; var after = info.after ?? new string[0]; var debug = info.debug ?? false; patchInfo.AddPostfix(info.method, owner, priority, before, after, debug); }
/// <summary>Serializes a patch info</summary> /// <param name="patchInfo">The patch info</param> /// <returns>A byte array</returns> /// internal static byte[] Serialize(this PatchInfo patchInfo) { #pragma warning disable XS0001 using (var streamMemory = new MemoryStream()) { var surrogateSelector = PatchSurrogate.GetSelector(); var formatter = new BinaryFormatter() { SurrogateSelector = surrogateSelector }; formatter.Serialize(streamMemory, patchInfo); return(streamMemory.GetBuffer()); } #pragma warning restore XS0001 }
/// <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); }
/// <summary>Unpatches a specific patch</summary> /// <param name="patch">The method of the patch</param> /// <returns>A <see cref="PatchProcessor"/> for chaining calls</returns> /// public PatchProcessor Unpatch(MethodInfo patch) { lock (locker) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } PatchFunctions.RemovePatch(patchInfo, patch); _ = PatchFunctions.UpdateWrapper(original, patchInfo); HarmonySharedState.UpdatePatchInfo(original, patchInfo); return(this); } }
/// <summary>Serializes a patch info</summary> /// <param name="patchInfo">The <see cref="PatchInfo"/></param> /// <returns>The serialized data</returns> /// internal static byte[] Serialize(this PatchInfo patchInfo) { #if NET50_OR_GREATER if (UseBinaryFormatter) { #endif using var streamMemory = new MemoryStream(); binaryFormatter.Serialize(streamMemory, patchInfo); return(streamMemory.GetBuffer()); #if NET50_OR_GREATER } else { return(JsonSerializer.SerializeToUtf8Bytes(patchInfo)); } #endif }
/// <summary>Unpatches the given patch</summary> /// <param name="patch">The patch</param> /// public void Unpatch(MethodInfo patch) { lock (locker) { foreach (var original in originals) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } PatchFunctions.RemovePatch(patchInfo, patch); PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id); HarmonySharedState.UpdatePatchInfo(original, patchInfo); } } }
/// <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 patcher = original.GetMethodPatcher(); var dmd = patcher.PrepareOriginal(); if (dmd != null) { var ctx = new ILContext(dmd.Definition); HarmonyManipulator.Manipulate(original, patchInfo, ctx); } try { return(patcher.DetourTo(dmd?.Generate()) as MethodInfo); } catch (Exception ex) { throw HarmonyException.Create(ex, dmd?.Definition?.Body); } }
public static void UpdatePatchInfo(MethodBase methodBase, PatchInfo patchInfo) { // skip }
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 { } }
/// <summary>Removes a transpiler</summary> /// <param name="patchInfo">The patch info</param> /// <param name="owner">The owner (Harmony ID)</param> /// internal static void RemoveTranspiler(PatchInfo patchInfo, string owner) { patchInfo.RemoveTranspiler(owner); }
/// <summary>Removes a postfix</summary> /// <param name="patchInfo">The patch info</param> /// <param name="owner">The owner (Harmony ID)</param> /// internal static void RemovePostfix(PatchInfo patchInfo, string owner) { patchInfo.RemovePostfix(owner); }
/// <summary>Removes a patch method</summary> /// <param name="patchInfo">The patch info</param> /// <param name="patch">The patch method</param> /// internal static void RemovePatch(PatchInfo patchInfo, MethodInfo patch) { patchInfo.RemovePatch(patch); }
/// <summary>Removes a finalizer</summary> /// <param name="patchInfo">The patch info</param> /// <param name="owner">The owner (Harmony ID)</param> /// internal static void RemoveFinalizer(PatchInfo patchInfo, string owner) { patchInfo.RemoveFinalizer(owner); }
internal static void UpdatePatchInfo(MethodBase method, PatchInfo patchInfo) { GetState()[method] = patchInfo.Serialize(); }
internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement, PatchInfo patchInfo) { var bytes = patchInfo.Serialize(); var info = GetState(); lock (info.state) info.state[original] = bytes; lock (info.originals) info.originals[replacement] = original; }
public static DynamicMethod UpdateWrapper(MethodBase original, PatchInfo info, string id) { original.GetMethodPatcher().Apply(); return(null); }
internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement, PatchInfo patchInfo) { var bytes = patchInfo.Serialize(); _ = WithState <object>(() => { state[original] = bytes; originals[replacement] = original; return(null); }); }