public static void ProfilePatch() { MethodTransplanting.PatchMethods(typeof(H_InfoCard)); Modbase.Harmony.Patch(AccessTools.Method(typeof(StatsReportUtility), nameof(StatsReportUtility.DrawStatsReport), new[] { typeof(Rect), typeof(Thing) }), new HarmonyMethod(typeof(H_InfoCard), nameof(FUUUCK))); }
private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> codeInstructions) { var enumerable = codeInstructions.ToList(); try { List <CodeInstruction> instructions = enumerable; for (int i = 0; i < instructions.Count; i++) { if (!IsFunctionCall(instructions[i].opcode)) { continue; } if (!(instructions[i].operand is MethodInfo meth)) { continue; } // Check for constrained if (i != 0 && instructions[i - 1].opcode == OpCodes.Constrained) { continue; } // Make sure it is not an analyzer profiling method if (meth.DeclaringType.FullName.Contains("Analyzer.Profiling")) { continue; } var key = Utility.GetMethodKey(meth); var index = MethodInfoCache.AddMethod(key, meth); var inst = MethodTransplanting.ReplaceMethodInstruction( instructions[i], key, GUIController.types[__originalMethod.DeclaringType + ":" + __originalMethod.Name + "-int"], index); instructions[i] = inst; } return(instructions); } catch (Exception e) { #if DEBUG ThreadSafeLogger.Error($"Failed to patch the internal method {__originalMethod.DeclaringType.FullName}:{__originalMethod.Name}, failed with the error " + e.Message); #else if (Settings.verboseLogging) { ThreadSafeLogger.Warning($"Failed to patch the internal method {__originalMethod.DeclaringType.FullName}:{__originalMethod.Name}, failed with the error " + e.Message); } #endif return(enumerable); } }
private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> instructions) { var inst = PatchProcessor.GetOriginalInstructions(__originalMethod); var modInstList = instructions.ToList(); var insts = new Myers <CodeInstruction>(inst.ToArray(), modInstList.ToArray(), methComparer); insts.Compute(); var key = Utility.GetMethodKey(__originalMethod as MethodInfo); var index = MethodInfoCache.AddMethod(key, __originalMethod as MethodInfo); foreach (var thing in insts.changeSet) { // We only want added methods if (thing.change != ChangeType.Added) { continue; } if (!InternalMethodUtility.IsFunctionCall(thing.value.opcode) || !(thing.value.operand is MethodInfo meth)) { continue; } // swap our instruction var replaceInstruction = MethodTransplanting.ReplaceMethodInstruction( thing.value, key, typeof(H_HarmonyTranspilersInternalMethods), index); // Find the place it was in our method, and replace the instruction (Optimisation Opportunity to improve this) for (var i = 0; i < modInstList.Count; i++) { var instruction = modInstList[i]; if (!InternalMethodUtility.IsFunctionCall(instruction.opcode)) { continue; } if (!(instruction.operand is MethodInfo info) || info.Name != meth.Name) { continue; } if (instruction != replaceInstruction) { modInstList[i] = replaceInstruction; } break; } } return(modInstList); }
public static void ProfilePatch() { try { MethodTransplanting.PatchMethods(typeof(H_HarmonyPatches)); } catch (Exception e) { ThreadSafeLogger.Error("Patching HarmonyPatches failed, errored with the message" + e.Message); } }
public static void ProfilePatch() { try { MethodTransplanting.PatchMethods(typeof(H_HarmonyPatches)); } catch (Exception e) { ThreadSafeLogger.ReportException(e, "Failed to patch HarmonyPatches"); } }
public static void ExecutePatch(CurrentInput mode, string strinput, Category cat) { try { var entry = cat == Category.Tick ? typeof(CustomProfilersTick) : typeof(CustomProfilersUpdate); List <MethodInfo> methods = null; var temp = mode switch { CurrentInput.Method => Utility.GetMethods(strinput), CurrentInput.Type => Utility.GetTypeMethods(AccessTools.TypeByName(strinput)), CurrentInput.MethodHarmony => Utility.GetMethodsPatching(strinput), CurrentInput.SubClasses => Utility.SubClassImplementationsOf(AccessTools.TypeByName(strinput), m => true), CurrentInput.TypeHarmony => Utility.GetMethodsPatchingType(AccessTools.TypeByName(strinput)), _ => null, }; if (temp is null) { if (mode == CurrentInput.InternalMethod) { Utility.PatchInternalMethod(strinput, cat); } else { Utility.PatchAssembly(strinput, cat); } return; } methods = temp.ToList(); if (methods.Count == 0) { Messages.Message($"Failed to find the method(s) represented by {strinput}", MessageTypeDefOf.CautionInput, false); return; } Messages.Message(methods.Count != 1 ? $"Patching {methods.Count} methods in the category {cat}" : $"Patching {Utility.GetSignature(methods[0])} in the category {cat}", MessageTypeDefOf.CautionInput, false); MethodTransplanting.UpdateMethods(entry, methods.ToList()); GUIController.Tab(cat).collapsed = false; var entryName = (cat == Category.Tick) ? "Custom Tick" : "Custom Update"; GUIController.SwapToEntry(entryName); } catch (Exception e) { ThreadSafeLogger.ReportException(e, $"Failed to process search bar input"); } }
private static void PatchAssemblyFull(string key, List <Assembly> assemblies) { var meths = new HashSet <MethodInfo>(); foreach (var asm in assemblies) { try { var asmName = $"{asm.GetName().Name}.dll"; if (patchedAssemblies.Contains(asm.FullName)) { Warn($"patching {asmName} failed, already patched"); continue; } patchedAssemblies.Add(asm.FullName); foreach (var type in AccessTools.GetTypesFromAssembly(asm)) { var methods = AccessTools.GetDeclaredMethods(type).ToList(); foreach (var m in methods) { try { if (ValidMethod(m) && m.DeclaringType == type) { meths.TryAdd(m); } } catch (Exception e) { ReportException(e, $"Skipping method {GetSignature(m)}"); } } } } catch (Exception e) { ReportException(e, $"Failed to patch the assembly {asm.FullName}"); } } var asms = assemblies.Select(a => a.GetName().Name + ".dll").Join(); var asmString = assemblies.Count > 1 ? "assemblies" : "assembly"; Messages.Message($"Attempting to patch {meths.Count} methods from the {asmString} [{asms}]", MessageTypeDefOf.CautionInput, false); MethodTransplanting.UpdateMethods(GUIController.types[key], meths); }
public static void ClearPatchCaches() { patchedAssemblies.Clear(); patchedTypes.Clear(); patchedMethods.Clear(); InternalMethodUtility.ClearCaches(); MethodTransplanting.ClearCaches(); TranspilerMethodUtility.ClearCaches(); MethodInfoCache.ClearCache(); #if DEBUG ThreadSafeLogger.Message("[Analyzer] Cleared all caches"); #endif }
private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> instructions) { var inst = PatchProcessor.GetOriginalInstructions(__originalMethod); var modInstList = instructions.ToList(); var insts = new Myers <CodeInstruction>(inst.ToArray(), modInstList.ToArray(), methComparer); insts.Compute(); var key = Utility.GetMethodKey(__originalMethod); var index = MethodInfoCache.AddMethod(key, __originalMethod); foreach (var thing in insts.changeSet) { // We only want added methods if (thing.change != ChangeType.Added) { continue; } if (!Utility.ValidCallInstruction(thing.value, null, out var meth, out _)) { continue; } if (!(meth is MethodInfo)) { continue; } // swap our instruction var replaceInstruction = MethodTransplanting.ReplaceMethodInstruction( thing.value, key, typeof(H_HarmonyTranspilersInternalMethods), index); modInstList[thing.rIndex] = replaceInstruction; } return(modInstList); }
private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> codeInstructions) { try { var instructions = codeInstructions.ToList(); for (int i = 0; i < instructions.Count; i++) { if (!Utility.ValidCallInstruction(instructions[i], i == 0 ? null : instructions[i - 1], out var meth, out var key)) { continue; } var index = MethodInfoCache.AddMethod(key, meth); var inst = MethodTransplanting.ReplaceMethodInstruction( instructions[i], key, GUIController.types[__originalMethod.DeclaringType + ":" + __originalMethod.Name + "-int"], index); instructions[i] = inst; } return(instructions); } catch (Exception e) { #if DEBUG ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}"); #else if (Settings.verboseLogging) { ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}"); } #endif return(codeInstructions); } }
private static void PatchAssemblyFull(string key, List <Assembly> assemblies) { var meths = new HashSet <MethodInfo>(); foreach (var assembly in assemblies) { try { if (patchedAssemblies.Contains(assembly.FullName)) { Warn($"patching {assembly.FullName} failed, already patched"); return; } patchedAssemblies.Add(assembly.FullName); foreach (var type in assembly.GetTypes()) { foreach (var method in AccessTools.GetDeclaredMethods(type).Where(m => ValidMethod(m) && m.DeclaringType == type)) { if (!meths.Contains(method)) { meths.Add(method); } } } Notify($"Patched {assembly.FullName}"); } catch (Exception e) { Error($"Patching {assembly.FullName} failed, {e.Message}"); return; } } MethodTransplanting.UpdateMethods(GUIController.types[key], meths); }
public static void ExecutePatch() { try { if (patchType == Category.Tick) { switch (input) { case CurrentInput.Method: MethodTransplanting.UpdateMethods(typeof(CustomProfilersTick), Utility.GetMethods(currentInput)); break; case CurrentInput.Type: MethodTransplanting.UpdateMethods(typeof(CustomProfilersTick), Utility.GetTypeMethods(AccessTools.TypeByName(currentInput))); break; case CurrentInput.MethodHarmony: MethodTransplanting.UpdateMethods(typeof(CustomProfilersTick), Utility.GetMethodsPatching(currentInput)); break; case CurrentInput.SubClasses: MethodTransplanting.UpdateMethods(typeof(CustomProfilersTick), Utility.SubClassImplementationsOf(AccessTools.TypeByName(currentInput), m => true)); break; case CurrentInput.TypeHarmony: MethodTransplanting.UpdateMethods(typeof(CustomProfilersTick), Utility.GetMethodsPatchingType(AccessTools.TypeByName(currentInput))); break; case CurrentInput.InternalMethod: Utility.PatchInternalMethod(currentInput, Category.Tick); return; case CurrentInput.Assembly: Utility.PatchAssembly(currentInput, Category.Tick); return; } GUIController.SwapToEntry("Custom Tick"); } else { switch (input) { case CurrentInput.Method: MethodTransplanting.UpdateMethods(typeof(CustomProfilersUpdate), Utility.GetMethods(currentInput)); break; case CurrentInput.Type: MethodTransplanting.UpdateMethods(typeof(CustomProfilersUpdate), Utility.GetTypeMethods(AccessTools.TypeByName(currentInput))); break; case CurrentInput.MethodHarmony: MethodTransplanting.UpdateMethods(typeof(CustomProfilersUpdate), Utility.GetMethodsPatching(currentInput)); break; case CurrentInput.SubClasses: MethodTransplanting.UpdateMethods(typeof(CustomProfilersUpdate), Utility.SubClassImplementationsOf(AccessTools.TypeByName(currentInput), m => true)); break; case CurrentInput.TypeHarmony: MethodTransplanting.UpdateMethods(typeof(CustomProfilersUpdate), Utility.GetMethodsPatchingType(AccessTools.TypeByName(currentInput))); break; case CurrentInput.InternalMethod: Utility.PatchInternalMethod(currentInput, Category.Update); return; case CurrentInput.Assembly: Utility.PatchAssembly(currentInput, Category.Update); return; } GUIController.SwapToEntry("Custom Update"); } } catch (Exception e) { ThreadSafeLogger.Error($"Failed to process input, failed with the error {e.Message}"); } }
public static void ProfilePatch() { Modbase.Harmony.Patch(AccessTools.Method(typeof(ThinkNode_Priority), nameof(ThinkNode_Priority.TryIssueJobPackage)), new HarmonyMethod(typeof(H_GetLord), nameof(Fringe))); MethodTransplanting.UpdateMethods(typeof(H_GetLord), Utility.GetTypeMethods(typeof(Lord)).ToList()); }