public static void PatchAssembly(string name, Category type) { var mod = LoadedModManager.RunningMods.FirstOrDefault(m => m.Name == name || m.PackageId == name.ToLower()); if (mod == null) { Error($"Failed to locate the mod {name}"); return; } Notify($"Assembly count: {mod.assemblies?.loadedAssemblies?.Count ?? 0}"); var assemblies = mod?.assemblies?.loadedAssemblies?.Where(ValidAssembly).ToList(); Notify($"Assembly count after removing Harmony/Cecil/Multiplayer/UnityEngine: {assemblies?.Count}"); if (assemblies != null && assemblies.Count() != 0) { GUIController.AddEntry(mod.Name + "-prof", type); GUIController.SwapToEntry(mod.Name + "-prof"); Task.Factory.StartNew(() => PatchAssemblyFull(mod.Name + "-prof", assemblies.ToList())); } else { Error($"Failed to patch {name} - There are no assemblies"); } }
private static void PatchInternalMethodFull(MethodInfo method, Category category) { try { var guiEntry = method.DeclaringType + ":" + method.Name + "-int"; GUIController.AddEntry(guiEntry, category); GUIController.SwapToEntry(guiEntry); InternalMethodUtility.PatchedInternals.Add(method); Task.Factory.StartNew(() => { try { Modbase.Harmony.Patch(method, transpiler: InternalMethodUtility.InternalProfiler); } catch (Exception e) { Error($"Failed to internal patch method {method.DeclaringType.FullName}:{method.Name}, failed with the exep " + e.Message); } }); } catch (Exception e) { Error("Failed to patch internal methods, failed with the error " + e.Message); InternalMethodUtility.PatchedInternals.Remove(method); } }
private static void PatchInternalMethodFull(MethodInfo method, Category category) { try { bool Valid() { var bytes = method.GetMethodBody()?.GetILAsByteArray(); if (bytes == null) { return(false); } if (bytes.Length == 0) { return(false); } if (bytes.Length == 1 && bytes.First() == 0x2A) { return(false); } return(true); } if (Valid() == false) { Error("Can not patch this method, this is likely a method which is virtually dispatched or marked as external, and thus can not be generically examined."); return; } var guiEntry = method.DeclaringType + ":" + method.Name + "-int"; GUIController.AddEntry(guiEntry, category); GUIController.SwapToEntry(guiEntry); InternalMethodUtility.PatchedInternals.Add(method); Task.Factory.StartNew(() => { try { Modbase.Harmony.Patch(method, transpiler: InternalMethodUtility.InternalProfiler); } catch (Exception e) { ReportException(e, $"Failed to patch the internal methods within {Utility.GetSignature(method, false)}"); } }); } catch (Exception e) { ReportException(e, "Failed to set up state to patch internal methods"); InternalMethodUtility.PatchedInternals.Remove(method); } }
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"); } }
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}"); } }
private static void DrawEntry(ref Rect row, KeyValuePair <Entry, Type> entry) { row = listing.GetRect(30f); Widgets.DrawHighlightIfMouseover(row); if (GUIController.CurrentEntry == entry.Key) { Widgets.DrawOptionSelected(row); } row.x += 20f; yOffset += 30f; Widgets.Label(row, entry.Key.name); if (Widgets.ButtonInvisible(row)) { GUIController.SwapToEntry(entry.Key.name); } if (entry.Key.isClosable) { if (Input.GetMouseButtonDown(1) && row.Contains(Event.current.mousePosition)) { List <FloatMenuOption> options = new List <FloatMenuOption>() { new FloatMenuOption("Close", () => GUIController.RemoveEntry(entry.Key.name)) }; Find.WindowStack.Add(new FloatMenu(options)); } } TooltipHandler.TipRegion(row, entry.Key.tip); if (GUIController.CurrentEntry == entry.Key) { bool firstEntry = true; foreach (KeyValuePair <FieldInfo, Setting> keySetting in entry.Key.Settings) { if (keySetting.Key.FieldType == typeof(bool)) { row = listing.GetRect(30f); row.x += 20f; GUI.color = Widgets.OptionSelectedBGBorderColor; Widgets.DrawLineVertical(row.x, row.y, 15f); if (!firstEntry) { Widgets.DrawLineVertical(row.x, row.y - 15f, 15f); } row.x += 10f; Widgets.DrawLineHorizontal(row.x - 10f, row.y + 15f, 10f); GUI.color = Color.white; yOffset += 30f; bool cur = (bool)keySetting.Key.GetValue(null); if (DubGUI.Checkbox(row, keySetting.Value.name, ref cur)) { keySetting.Key.SetValue(null, cur); GUIController.ResetProfilers(); } } if (keySetting.Value.tip != null) { TooltipHandler.TipRegion(row, keySetting.Value.tip); } firstEntry = false; } } }