SMAPI/ModLoader/Harmony/PatchFunctions.cs

99 lines
3.2 KiB
C#

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<ILInstruction> GetInstructions(ILGenerator generator, MethodBase method)
{
return MethodBodyReader.GetInstructions(generator, method);
}
public static List<MethodInfo> 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;
}
}
}