/// <summary>Gets Harmony version for all active Harmony instances</summary> /// <param name="currentVersion">[out] The current Harmony version</param> /// <returns>A dictionary containing assembly versions keyed by Harmony IDs</returns> /// public static Dictionary <string, Version> VersionInfo(out Version currentVersion) { currentVersion = typeof(HarmonyInstance).Assembly.GetName().Version; var assemblies = new Dictionary <string, Assembly>(); GetAllPatchedMethods().Do(method => { var info = HarmonySharedState.GetPatchInfo(method); info.prefixes.Do(fix => assemblies[fix.owner] = fix.patch.DeclaringType.Assembly); info.postfixes.Do(fix => assemblies[fix.owner] = fix.patch.DeclaringType.Assembly); info.transpilers.Do(fix => assemblies[fix.owner] = fix.patch.DeclaringType.Assembly); }); var result = new Dictionary <string, Version>(); assemblies.Do(info => { var assemblyName = info.Value.GetReferencedAssemblies().FirstOrDefault(a => a.FullName.StartsWith("0Harmony, Version")); if (assemblyName != null) { result[info.Key] = assemblyName.Version; } }); return(result); }
/// <summary> /// 执行Patch /// </summary> /// <returns></returns> public PatchInfoData Patch(PatchFlags flags) { PatchInfo patchInfo = null; lock (locker) { #if RECORD_PATCH_STATE patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } #endif patchInfo = new PatchInfo(); PatchFunctions.AddPrefix(patchInfo, instance.id, prefix); PatchFunctions.AddPostfix(patchInfo, instance.id, postfix); PatchFunctions.AddTranspiler(patchInfo, instance.id, transpiler); PatchFunctions.UpdateWrapper(original, patchInfo, flags); #if RECORD_PATCH_STATE HarmonySharedState.UpdatePatchInfo(original, patchInfo); #endif } return(patchInfo.patchdata); }
/// <summary>Unpatches patches of a given type and/or Harmony ID</summary> /// <param name="type">The patch type</param> /// <param name="harmonyID">Harmony ID or (*) for any</param> /// public void Unpatch(HarmonyPatchType type, string harmonyID) { lock (locker) { foreach (var original in originals) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix) { PatchFunctions.RemovePrefix(patchInfo, harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix) { PatchFunctions.RemovePostfix(patchInfo, harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler) { PatchFunctions.RemoveTranspiler(patchInfo, harmonyID); } PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id); HarmonySharedState.UpdatePatchInfo(original, patchInfo); } } }
public void Unpatch(HarmonyPatchType type, string harmonyID) { lock (locker) { foreach (var original in originals) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix) { PatchFunctions.RemovePrefix(patchInfo, harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix) { PatchFunctions.RemovePostfix(patchInfo, harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler) { PatchFunctions.RemoveTranspiler(patchInfo, harmonyID); } PatchHandler.Get(original).Apply(); } } }
public void Unpatch(HarmonyPatchType type, string harmonyID) { var obj = locker; lock (obj) { foreach (var methodBase in originals) { var patchInfo = HarmonySharedState.GetPatchInfo(methodBase) ?? new PatchInfo(); if (type == HarmonyPatchType.All || type == HarmonyPatchType.Prefix) { PatchFunctions.RemovePrefix(patchInfo, harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Postfix) { PatchFunctions.RemovePostfix(patchInfo, harmonyID); } if (type == HarmonyPatchType.All || type == HarmonyPatchType.Transpiler) { PatchFunctions.RemoveTranspiler(patchInfo, harmonyID); } PatchFunctions.UpdateWrapper(methodBase, patchInfo, instance.Id); HarmonySharedState.UpdatePatchInfo(methodBase, patchInfo); } } }
public void Patch() { var obj = locker; lock (obj) { foreach (var methodBase in originals) { if (methodBase == null) { throw new NullReferenceException("original"); } if (RunMethod <HarmonyPrepare, bool>(true, methodBase)) { var patchInfo = HarmonySharedState.GetPatchInfo(methodBase) ?? new PatchInfo(); PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix); PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix); PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler); PatchFunctions.UpdateWrapper(methodBase, patchInfo, instance.Id); HarmonySharedState.UpdatePatchInfo(methodBase, patchInfo); RunMethod <HarmonyCleanup>(methodBase); } } } }
public static IEnumerable <MethodBase> AllPatchedMethods() { lock (locker) { return(HarmonySharedState.GetPatchedMethods()); } }
public List <DynamicMethod> Patch() { lock (locker) { var dynamicMethods = new List <DynamicMethod>(); foreach (var original in originals) { if (original == null) { throw new NullReferenceException("original"); } var individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, original); if (individualPrepareResult) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix); PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix); PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler); dynamicMethods.Add(PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id)); HarmonySharedState.UpdatePatchInfo(original, patchInfo); RunMethod <HarmonyCleanup>(original); } } return(dynamicMethods); } }
private static IEnumerable <CodeInstruction> UnhollowerTranspiler(MethodBase method, IEnumerable <CodeInstruction> instructionsIn) { List <CodeInstruction> instructions = new List <CodeInstruction>(instructionsIn); PatchInfo patchInfo = HarmonySharedState.GetPatchInfo(method); IntPtr copiedMethodInfo = patchInfo.copiedMethodInfoPointer; bool found = false; int replaceIdx = 0; int replaceCount = 0; for (int i = instructions.Count - 2; i >= 0; --i) { if (instructions[i].opcode != OpCodes.Ldsfld) { continue; } found = true; CodeInstruction next = instructions[i + 1]; if (next.opcode == OpCodes.Call && ((MethodInfo)next.operand).Name == "il2cpp_object_get_virtual_method") { // Virtual method: Replace the sequence // - ldarg.0 // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::Il2CppObjectBaseToPtr(class [UnhollowerBaseLib] UnhollowerBaseLib.Il2CppObjectBase) // - ldsfld native int SomeClass::NativeMethodInfoPtr_Etc // - call native int[UnhollowerBaseLib] UnhollowerBaseLib.IL2CPP::il2cpp_object_get_virtual_method(native int, native int) replaceIdx = i - 2; replaceCount = 4; } else { // Everything else: Just replace the static load replaceIdx = i; replaceCount = 1; } break; } if (!found) { MelonLogger.Error("Harmony transpiler could not rewrite Unhollower method. Expect a stack overflow."); return(instructions); } CodeInstruction[] replacement = { new CodeInstruction(OpCodes.Ldc_I8, copiedMethodInfo.ToInt64()), new CodeInstruction(OpCodes.Conv_I) }; instructions.RemoveRange(replaceIdx, replaceCount); instructions.InsertRange(replaceIdx, replacement); return(instructions); }
public static Patches IsPatched(MethodBase method) { var patchInfo = HarmonySharedState.GetPatchInfo(method); if (patchInfo == null) { return(null); } return(new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers)); }
public Dictionary <string, Version> VersionInfo(out Version currentVersion) { currentVersion = Assembly.GetExecutingAssembly().GetName().Version; var assemblies = new Dictionary <string, Assembly>(); Action <Patch> a1 = null; Action <Patch> a2 = null; Action <Patch> a3 = null; GetPatchedMethods().Do(delegate(MethodBase method) { var patchInfo = HarmonySharedState.GetPatchInfo(method); IEnumerable <Patch> prefixes = patchInfo.prefixes; Action <Patch> action; if ((action = a1) == null) { action = (a1 = delegate(Patch fix) { assemblies[fix.owner] = fix.patch.DeclaringType.Assembly; }); } prefixes.Do(action); IEnumerable <Patch> postfixes = patchInfo.postfixes; Action <Patch> action2; if ((action2 = a2) == null) { action2 = (a2 = delegate(Patch fix) { assemblies[fix.owner] = fix.patch.DeclaringType.Assembly; }); } postfixes.Do(action2); IEnumerable <Patch> transpilers = patchInfo.transpilers; Action <Patch> action3; if ((action3 = a3) == null) { action3 = (a3 = delegate(Patch fix) { assemblies[fix.owner] = fix.patch.DeclaringType.Assembly; }); } transpilers.Do(action3); }); var result = new Dictionary <string, Version>(); assemblies.Do(delegate(KeyValuePair <string, Assembly> info) { var assemblyName = info.Value.GetReferencedAssemblies() .FirstOrDefault(a => a.FullName.StartsWith("0Harmony, Version")); if (assemblyName != null) { result[info.Key] = assemblyName.Version; } }); return(result); }
public static IEnumerable <MethodBase> AllPatchedMethods() { var obj = locker; IEnumerable <MethodBase> patchedMethods; lock (obj) { patchedMethods = HarmonySharedState.GetPatchedMethods(); } return(patchedMethods); }
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); bool isIl2Cpp = UnhollowerSupport.IsGeneratedAssemblyType(original.DeclaringType); if (isIl2Cpp) { if (sortedTranspilers.Count > 0) { throw new NotSupportedException("IL2CPP patches cannot use transpilers (got " + sortedTranspilers.Count + ")"); } if (patchInfo.copiedMethodInfoPointer == IntPtr.Zero) { IntPtr origMethodPtr = UnhollowerSupport.MethodBaseToIl2CppMethodInfoPointer(original); patchInfo.copiedMethodInfoPointer = CopyMethodInfoStruct(origMethodPtr); HarmonySharedState.UpdatePatchInfo(original, patchInfo); } sortedTranspilers.Add(AccessTools.DeclaredMethod(typeof(PatchFunctions), "UnhollowerTranspiler")); } var replacement = MethodPatcher.CreatePatchedMethod(original, instanceID, sortedPrefixes, sortedPostfixes, sortedTranspilers); if (replacement == null) { throw new MissingMethodException("Cannot create dynamic replacement for " + original.FullDescription()); } if (isIl2Cpp) { DynamicMethod il2CppShim = CreateIl2CppShim(replacement, original); InstallIl2CppPatch(patchInfo, il2CppShim); PatchTools.RememberObject(original, new PotatoTuple { First = replacement, Second = il2CppShim }); } else { 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); }
public void Unpatch(MethodInfo patch) { var obj = locker; lock (obj) { foreach (var methodBase in originals) { var patchInfo = HarmonySharedState.GetPatchInfo(methodBase) ?? new PatchInfo(); PatchFunctions.RemovePatch(patchInfo, patch); PatchFunctions.UpdateWrapper(methodBase, patchInfo, instance.Id); HarmonySharedState.UpdatePatchInfo(methodBase, patchInfo); } } }
public void Patch() { lock (locker) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix); PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix); PatchFunctions.AddInfix(patchInfo, instance.Id, infix); PatchFunctions.UpdateWrapper(original, patchInfo); HarmonySharedState.UpdatePatchInfo(original, patchInfo); } }
public void Patch() { lock (locker) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix); PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix); PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler); PatchHandler.Get(original).Apply(); } }
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); PatchHandler.Get(original).Apply(); } } }
public List <DynamicMethod> Patch() { lock (locker) { var dynamicMethods = new List <DynamicMethod>(); foreach (var original in originals) { if (original == null) { throw new NullReferenceException("original"); } if ((original.DeclaringType.Assembly.GetCustomAttributes(typeof(HarmonyShield), false).Count() > 0) || (original.DeclaringType.GetCustomAttributes(typeof(HarmonyShield), false).Count() > 0) || (original.GetCustomAttributes(typeof(HarmonyShield), false).Count() > 0)) { continue; } if (MelonDebug.IsEnabled() && UnhollowerSupport.IsGeneratedAssemblyType(original.DeclaringType)) { WarnIfTargetMethodInlined(original); } var individualPrepareResult = RunMethod <HarmonyPrepare, bool>(true, original); if (individualPrepareResult) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { patchInfo = new PatchInfo(); } PatchFunctions.AddPrefix(patchInfo, instance.Id, prefix); PatchFunctions.AddPostfix(patchInfo, instance.Id, postfix); PatchFunctions.AddTranspiler(patchInfo, instance.Id, transpiler); dynamicMethods.Add(PatchFunctions.UpdateWrapper(original, patchInfo, instance.Id)); HarmonySharedState.UpdatePatchInfo(original, patchInfo); RunMethod <HarmonyCleanup>(original); } } return(dynamicMethods); } }
public void Restore() { lock (locker) { var patchInfo = HarmonySharedState.GetPatchInfo(original); if (patchInfo == null) { return; } PatchFunctions.RemovePrefix(patchInfo, prefix); PatchFunctions.RemovePostfix(patchInfo, postfix); PatchFunctions.RemoveTranspiler(patchInfo, transpiler); PatchFunctions.UpdateWrapper(original, patchInfo); HarmonySharedState.UpdatePatchInfo(original, patchInfo); } }
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); } } }
public static Patches GetPatchInfo(MethodBase method) { var obj = locker; Patches result; lock (obj) { var patchInfo = HarmonySharedState.GetPatchInfo(method); if (patchInfo == null) { result = null; } else { result = new Patches(patchInfo.prefixes, patchInfo.postfixes, patchInfo.transpilers, patchInfo.finalizers); } } return(result); }
public void Apply() { PatchMethod[] ToPatchMethod(Patch[] patches) { return(patches.Select(p => new PatchMethod { after = p.after, before = p.before, method = p.patch, priority = p.priority, owner = p.owner, }).ToArray()); } var info = HarmonySharedState.GetPatchInfo(mb); var state = new PatchInfoWrapper { prefixes = ToPatchMethod(info.prefixes), postfixes = ToPatchMethod(info.postfixes), transpilers = ToPatchMethod(info.transpilers), finalizers = new PatchMethod[0] }; var add = new PatchInfoWrapper { finalizers = new PatchMethod[0] }; var remove = new PatchInfoWrapper { finalizers = new PatchMethod[0] }; Diff(previousState.prefixes, state.prefixes, out add.prefixes, out remove.prefixes); Diff(previousState.postfixes, state.postfixes, out add.postfixes, out remove.postfixes); Diff(previousState.transpilers, state.transpilers, out add.transpilers, out remove.transpilers); previousState = state; HarmonyInterop.ApplyPatch(mb, add, remove); }
/// <summary>Gets a patched methods</summary> /// <returns>An enumeration of original methods</returns> /// public IEnumerable <MethodBase> GetPatchedMethods() { return(HarmonySharedState.GetPatchedMethods()); }
/// <summary>Gets the methods this instance has patched</summary> /// <returns>An enumeration of original methods</returns> /// public IEnumerable <MethodBase> GetPatchedMethods() { return(HarmonySharedState.GetPatchedMethods() .Where(original => GetPatchInfo(original).Owners.Contains(Id))); }