public override bool?IsApplicable(Game game) { var patchInfo = Harmony.GetPatchInfo(PureSpeedMethodInfo); if (AlreadyPatchedByOthers(patchInfo)) { return(false); } return(HashesMatch()); }
public static IEnumerable <MethodInfo> GetPatchMethods() { foreach (MethodBase mode in Harmony.GetAllPatchedMethods().ToList()) { Patches patchInfo = Harmony.GetPatchInfo(mode); foreach (var fix in patchInfo.Prefixes.Concat(patchInfo.Postfixes).Where(f => Utility.IsNotAnalyzerPatch(f.owner))) { yield return(fix.PatchMethod); } } }
public Info(MethodBase method) { Method = method; var info = Harmony.GetPatchInfo(Method); GetPlugins(info.Prefixes); GetPlugins(info.Postfixes); GetPlugins(info.Transpilers); GetPlugins(info.Finalizers); }
/// <summary> /// Gets information about what patched the method. /// </summary> /// <param name="method">The method to check.</param> /// <param name="message">The location where the message will be stored.</param> internal static void GetPatchInfo(MethodBase method, StringBuilder message) { var patches = Harmony.GetPatchInfo(method); if (patches != null) { GetPatchInfo(patches.Prefixes, "Prefixed", message); GetPatchInfo(patches.Postfixes, "Postfixed", message); GetPatchInfo(patches.Transpilers, "Transpiled", message); } }
private static int wikiModInstallStatus; // 0: not checked, 1: installed, 2: not installed internal static void Patch(Harmony harmonyInstance, bool doInspectorButton) { if (harmonyInstance == null) { return; } var method = typeof(Dialog_InfoCard).GetMethod("DoWindowContents", BindingFlags.Public | BindingFlags.Instance); if (method == null) { Log.Error($"Failed to get method Dialog_InfoCard.DoWindowContents to patch. Did Rimworld update in a major way?"); return; } var postfix = typeof(InspectorPatch).GetMethod("InGameWikiPostfix", BindingFlags.NonPublic | BindingFlags.Static); if (postfix == null) { Log.Error("Failed to get local patch method..."); return; } var patch = new HarmonyMethod(postfix); bool canPatch = true; var patches = Harmony.GetPatchInfo(method); if (patches != null) { foreach (var pf in patches.Postfixes) { if (pf.PatchMethod.Name == "InGameWikiPostfix") { canPatch = false; break; } else { Log.Warning($"There is already a postfix on Dialog_InfoCard.DoWindowContents: {pf.PatchMethod.Name} by {pf.owner}. This could affect functionality of wiki patch."); } } } if (canPatch) { if (doInspectorButton) { harmonyInstance.Patch(method, postfix: patch); } Log.Message($"<color=cyan>Patched game for in-game wiki. Inspector button is {(doInspectorButton ? "enabled" : "<color=red>disabled</color>")}</color>"); } }
public bool IsApplicable(Game game) { { var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo1); if (AlreadyPatchedByOthers(patchInfo)) { return(false); } var bytes = TargetMethodInfo1.GetCilBytes(); if (bytes == null) { return(false); } var hash = bytes.GetSha256(); if (!hash.SequenceEqual(new byte[] { 0x5B, 0x47, 0x05, 0x79, 0x5A, 0x5D, 0xCB, 0xFC, 0xFA, 0x46, 0x21, 0x96, 0x00, 0x94, 0x8D, 0xCC, 0xC2, 0xE2, 0x35, 0x7F, 0x70, 0x0D, 0x64, 0xD5, 0x08, 0xAA, 0x8F, 0x2B, 0xA5, 0x0B, 0xF3, 0x4B })) { return(false); } } { var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo2); if (AlreadyPatchedByOthers(patchInfo)) { return(false); } var bytes = TargetMethodInfo2.GetCilBytes(); if (bytes == null) { return(false); } var hash = bytes.GetSha256(); if (!hash.SequenceEqual(new byte[] { 0x0B, 0xA1, 0x1A, 0x7D, 0x20, 0x6B, 0xC2, 0xD2, 0x3C, 0xEA, 0xF2, 0xCB, 0x83, 0x7F, 0x88, 0x14, 0x7D, 0xE2, 0x90, 0x71, 0x2F, 0xE0, 0x4D, 0x38, 0xE5, 0x47, 0xCC, 0x08, 0x62, 0x1E, 0x92, 0x26 })) { return(false); } } return(true); }
public static void CheckAndApplyCleaveCompatibility() { var methodBases = Harmony.GetAllPatchedMethods(); foreach (var method in methodBases) { if (Harmony.GetPatchInfo(method).Owners.Contains("xorberax.cutthrougheveryone")) { ApplyCompatibility(); } } }
private void Awake() { Logger = base.Logger; Logger.Log(LogLevel.Debug, "Core pre"); _timeStopsOnJump = Config.Bind("General", "Time Stops On Jump", false, "Insert funny JoJoke™ here. This one gets better with the timescale plugin from the CursedDlls."); _shortcutPrintLayerAndTagsInfo = Config.Bind("Keybinds - Debug", "Print Layer and Tags Info", new KeyboardShortcut(KeyCode.L, KeyCode.LeftShift), "Prints all Layers and Tags."); _shortcutPrintAllStreamingAssetsBundles = Config.Bind("Keybinds - Debug", "Print All StreamingAssets Bundles", new KeyboardShortcut(KeyCode.A, KeyCode.LeftShift), "Prints all prefabs in StreamingAssets, and every ItemSpawnerID."); _shortcutTelePlayerToOrigin = Config.Bind("Keybinds - Player", "Teleport Player to Origin", new KeyboardShortcut(KeyCode.Z), "Teleports the player rig to the origin of the level."); _shortcutTelePlayerToReset = Config.Bind("Keybinds - Player", "Teleport Player to Reset", new KeyboardShortcut(KeyCode.R), "Teleports the player rig to the reset point of the level."); _shortcutTelePlayer2mForward = Config.Bind("Keybinds - Player", "Teleport Player 2m Forward", new KeyboardShortcut(KeyCode.F), "Teleports the player rig 2 meters in whatever direction the player is looking in."); _shortcutSpawnModPanelV2 = Config.Bind("Keybinds - Misc", "Spawn ModPanelV2", new KeyboardShortcut(KeyCode.M, KeyCode.LeftAlt), "Spawns ModPanelV2 in an empty quickbelt slot, or on the floor if none are free."); _shortcutScrambleMaterials = Config.Bind("Keybinds - Misc", "Scramble Materials", new KeyboardShortcut(KeyCode.T, KeyCode.LeftAlt), "WARNING: SLOW AND DUMB\nScrambles all materials in the scene."); _shortcutScrambleMeshes = Config.Bind("Keybinds - Misc", "Scramble Meshes", new KeyboardShortcut(KeyCode.Y, KeyCode.LeftAlt), "WARNING: SLOW AND DUMB\nScrambles all meshes in the scene."); //Environment.SetEnvironmentVariable("MONOMOD_DMD_TYPE", "cecil"); //Environment.SetEnvironmentVariable("MONOMOD_DMD_DUMP", "./mmdump"); Harmony harmony = Harmony.CreateAndPatchAll(typeof(HarmonyPatches)); //this removes any other patches to the wrist menu's update function, //it's kind of terrible but it's the best method I could think to do //based on the types of patches that are made to the wrist menu MethodInfo FVRWristMenuUpdate = AccessTools.Method(typeof(FVRWristMenu), nameof(FVRWristMenu.Update)); if (FVRWristMenuUpdate != null) { Patches wristUpdatePatches = Harmony.GetPatchInfo(FVRWristMenuUpdate); foreach (Patch postfix in wristUpdatePatches.Postfixes) { if (postfix.owner != harmony.Id) { harmony.Unpatch(FVRWristMenuUpdate, HarmonyPatchType.All, postfix.owner); } } } //Environment.SetEnvironmentVariable("MONOMOD_DMD_DUMP", null); Logger.Log(LogLevel.Debug, "Core post"); }
public static IEnumerable <MethodInfo> GetMethodsPatchingType(Type type) { foreach (var meth in GetTypeMethods(type)) { var p = Harmony.GetPatchInfo(meth); foreach (var patch in p.Prefixes.Concat(p.Postfixes, p.Transpilers, p.Finalizers)) { yield return(patch.PatchMethod); } } }
public void Disable(UnityModManager.ModEntry modEntry, bool unpatch = false) { _logger = modEntry.Logger; using (ProcessLogger process = new ProcessLogger(_logger)) { process.Log("Disabling."); Enabled = false; // use try-catch to prevent the progression being disrupt by exceptions if (_eventHandlers != null) { process.Log("Raising events: OnDisable()"); for (int i = _eventHandlers.Count - 1; i >= 0; i--) { try { _eventHandlers[i].HandleModDisable(); } catch (Exception e) { Error(e); } } _eventHandlers = null; } if (unpatch) { Harmony harmonyInstance = new Harmony(modEntry.Info.Id); foreach (MethodBase method in harmonyInstance.GetPatchedMethods().ToList()) { Patches patchInfo = Harmony.GetPatchInfo(method); IEnumerable <Patch> patches = patchInfo.Transpilers.Concat(patchInfo.Postfixes).Concat(patchInfo.Prefixes) .Where(patch => patch.owner == modEntry.Info.Id); if (patches.Any()) { process.Log($"Unpatching: {patches.First().PatchMethod.DeclaringType.FullName} from {method.DeclaringType.FullName}.{method.Name}"); foreach (Patch patch in patches) { try { harmonyInstance.Unpatch(method, patch.PatchMethod); } catch (Exception e) { Error(e); } } } } Patched = false; } modEntry.OnSaveGUI -= HandleSaveGUI; Core = null; Settings = null; Version = null; _logger = null; process.Log("Disabled."); } }
public static void ProfilePatch() { Log.Message("Patching stats"); var jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValue)); var pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(Prefix)); var post = new HarmonyMethod(typeof(H_GetStatValue), nameof(Postfix)); Analyzer.harmony.Patch(jiff, pre, post); jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new [] { typeof(BuildableDef), typeof(StatDef), typeof(ThingDef) }); pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAb)); Analyzer.harmony.Patch(jiff, pre, post); jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new [] { typeof(AbilityDef), typeof(StatDef) }); pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAbility)); Analyzer.harmony.Patch(jiff, pre, post); jiff = AccessTools.Method(typeof(StatWorker), nameof(StatWorker.GetValue), new [] { typeof(StatRequest), typeof(bool) }); pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(GetValueDetour)); Analyzer.harmony.Patch(jiff, pre); var go = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPrefix)); var biff = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPostfix)); foreach (var allLeafSubclass in typeof(StatPart).AllSubclassesNonAbstract()) { var mef = AccessTools.Method(allLeafSubclass, nameof(StatPart.TransformValue)); if (mef.DeclaringType == allLeafSubclass) { var info = Harmony.GetPatchInfo(mef); var F = true; if (info != null) { foreach (var infoPrefix in info.Prefixes) { if (infoPrefix.PatchMethod == go.method) { F = false; } } } if (F) { Analyzer.harmony.Patch(mef, go, biff); } } } Log.Message("stats patched"); }
/// <summary> /// Checks to see if a patch with the specified method name (the method used in the /// patch class) and type is defined. /// </summary> /// <param name="instance">The Harmony instance to query for patches. Unused.</param> /// <param name="target">The target method to search for patches.</param> /// <param name="type">The patch type to look up.</param> /// <param name="name">The patch method name to look up (name as declared by patch owner).</param> /// <returns>true if such a patch was found, or false otherwise</returns> public static bool HasPatchWithMethodName(Harmony instance, MethodBase target, HarmonyPatchType type, string name) { bool found = false; if (target == null) { throw new ArgumentNullException(nameof(target)); } if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); } var patches = Harmony.GetPatchInfo(target); if (patches != null) { ICollection <Patch> patchList; switch (type) { case HarmonyPatchType.Prefix: patchList = patches.Prefixes; break; case HarmonyPatchType.Postfix: patchList = patches.Postfixes; break; case HarmonyPatchType.Transpiler: patchList = patches.Transpilers; break; case HarmonyPatchType.All: default: // All if (patches.Transpilers != null) { found = HasPatchWithMethodName(patches.Transpilers, name); } if (patches.Prefixes != null) { found = found || HasPatchWithMethodName(patches.Prefixes, name); } patchList = patches.Postfixes; break; } if (patchList != null) { found = found || HasPatchWithMethodName(patchList, name); } } return(found); }
/// <summary> /// Called when definitions (Defs) has been loaded. /// </summary> public void OnDefsLoaded() { Log.Message("[PrepareLanding] OnDefsLoaded"); DefsLoaded?.Invoke(); // // Try to patch Page_CreateWorldParams.CanDoNext // we need to do it here because the settings are only loaded at that time, and we need to check the // setting if we patch it or not. The verification is done in the patching method itself, not here. // var harmony = new Harmony("com.neitsa.preparelanding"); var canDoNextOriginalMethod = typeof(Page_CreateWorldParams).GetMethod("CanDoNext", BindingFlags.Instance | BindingFlags.NonPublic); if (canDoNextOriginalMethod == null) { Log.Message("[PrepareLanding] Could not find Page_CreateWorldParams.CanDoNext."); return; } var patches = Harmony.GetPatchInfo(canDoNextOriginalMethod); if (patches is null) { // method is not patched! Log.Message("[PrepareLanding] Manual Patching: Page_CreateWorldParams_CanDoNext"); var prefix = typeof(PatchCreateWorldParams).GetMethod("Page_CreateWorldParams_CanDoNext", BindingFlags.NonPublic | BindingFlags.Static); if (prefix is null) { Log.Message("[PrepareLanding] Could not find PatchCreateWorldParams.Page_CreateWorldParams_CanDoNext prefix."); return; } var replacementMethod = harmony.Patch(canDoNextOriginalMethod, new HarmonyMethod(prefix)); Log.Message($"[PrepareLanding] PatchCreateWorldParams.Page_CreateWorldParams_CanDoNext - patch done: {!(replacementMethod is null)}"); } else { // method is patched with a prefix... We can't add our own. Just log and bail out. Log.Message("[PrepareLanding] Page_CreateWorldParams.CanDoNext is already patched. Can't instantiate PreciseWorldGeneration..."); StringBuilder sb = new StringBuilder(); foreach (var patchesPrefix in patches.Prefixes) { sb.Append($"index: {patchesPrefix.index}; "); sb.Append($"owner: {patchesPrefix.owner}; "); sb.Append($"patch method: {patchesPrefix.PatchMethod}; "); sb.Append($"priority: {patchesPrefix.priority}; "); sb.Append($"before: {patchesPrefix.before}; "); sb.Append($"after: {patchesPrefix.after}"); sb.Append("\n----\n"); } Log.Message(sb.ToString()); } }
public static string getPotentialModConflicts() { string modsText = ""; IEnumerable <MethodBase> originalMethods = Harmony.GetAllPatchedMethods(); foreach (MethodBase originalMethod in originalMethods) { Patches patches = Harmony.GetPatchInfo(originalMethod); if (patches is null) { } else { bool isRimThreadedPrefixed = false; foreach (Patch patch in patches.Prefixes) { if (patch.owner.Equals("majorhoff.rimthreaded") && !RimThreadedHarmony.nonDestructivePrefixes.Contains(patch.PatchMethod) && (patches.Prefixes.Count > 1 || patches.Postfixes.Count > 0 || patches.Transpilers.Count > 0)) { isRimThreadedPrefixed = true; modsText += "\n ---Patch method: " + patch.PatchMethod.DeclaringType?.FullName + " " + patch.PatchMethod + "---\n"; modsText += " RimThreaded priority: " + patch.priority + "\n"; break; } } if (isRimThreadedPrefixed) { foreach (Patch patch in patches.Prefixes) { if (!patch.owner.Equals("majorhoff.rimthreaded")) { //Settings.modsText += "method: " + patch.PatchMethod + " - "; modsText += " owner: " + patch.owner + " - "; modsText += " FullName: " + patch.PatchMethod.DeclaringType?.FullName + "\n"; } } foreach (Patch patch in patches.Postfixes) { //Settings.modsText += "method: " + patch.PatchMethod + " - "; modsText += " owner: " + patch.owner + " - "; modsText += " FullName: " + patch.PatchMethod.DeclaringType?.FullName + "\n"; } foreach (Patch patch in patches.Transpilers) { //Settings.modsText += "method: " + patch.PatchMethod + " - "; modsText += " owner: " + patch.owner + " - "; modsText += " FullName: " + patch.PatchMethod.DeclaringType?.FullName + "\n"; } } } } return(modsText); }
public bool?IsApplicable(Game game) { var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo); if (AlreadyPatched(patchInfo)) { return(false); } var hash = TargetMethodInfo.MakeCilSignatureSha256(); return(hash.MatchesAnySha256(Hashes)); }
public static void Init() { harmony.PatchAll(Assembly.GetExecutingAssembly()); var actorMenuAwake = AccessTools.Method(typeof(ActorMenu), "Awake"); var postFixes = Harmony.GetPatchInfo(actorMenuAwake)?.Postfixes; if (postFixes == null || postFixes.Count == 0) { var patchedPostfix = new HarmonyMethod(typeof(Patches.ActorMenu_Awake_Hook), "Postfix", new[] { typeof(ActorMenu) }); harmony.Patch(actorMenuAwake, null, patchedPostfix); } }
public static void ProfilePatch() { var jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(BuildableDef), typeof(StatDef), typeof(ThingDef) }); var pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAb)); var post = new HarmonyMethod(typeof(H_GetStatValue), nameof(Postfix)); Modbase.Harmony.Patch(jiff, pre, post); jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(AbilityDef), typeof(StatDef), typeof(Pawn) }); pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAbility)); Modbase.Harmony.Patch(jiff, pre, post); jiff = AccessTools.Method(typeof(StatWorker), nameof(StatWorker.GetValue), new[] { typeof(StatRequest), typeof(bool) }); pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(GetValueDetour)); Modbase.Harmony.Patch(jiff, pre); HarmonyMethod go = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPrefix)); HarmonyMethod biff = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPostfix)); foreach (Type allLeafSubclass in typeof(StatPart).AllSubclassesNonAbstract()) { try { MethodInfo mef = AccessTools.Method(allLeafSubclass, nameof(StatPart.TransformValue), new Type[] { typeof(StatRequest), typeof(float).MakeByRefType() }); if (mef.DeclaringType == allLeafSubclass) { HarmonyLib.Patches info = Harmony.GetPatchInfo(mef); bool F = true; if (info != null) { foreach (Patch infoPrefix in info.Prefixes) { if (infoPrefix.PatchMethod == go.method) { F = false; } } } if (F) { Modbase.Harmony.Patch(mef, go, biff); } } } catch (Exception e) { ThreadSafeLogger.ReportException(e, $"Failed to patch {allLeafSubclass} from {allLeafSubclass.Assembly.FullName} for profiling"); } } }
public override bool?IsApplicable(Game game) // ReSharper disable once CompareOfFloatsByEqualityOperator { var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo); if (AlreadyPatchedByOthers(patchInfo)) { return(false); } var hash = TargetMethodInfo.MakeCilSignatureSha256(); return(hash.MatchesAnySha256(Hashes)); }
public static void DevLog(this ManualLogSource log, Harmony harmony) { foreach (MethodBase method in harmony.GetPatchedMethods()) { Patches patches = Harmony.GetPatchInfo(method); log.DevLog(string.Format("{0}::{1} patchers:", method.DeclaringType.FullName, method.Name)); log.DevLog(string.Join(" ", patches.Owners.ToArray())); LogPatchSegment(log, method, patches.Prefixes, "Prefixes:"); LogPatchSegment(log, method, patches.Transpilers, "Transpilers:"); LogPatchSegment(log, method, patches.Postfixes, "Postfixes:"); LogPatchSegment(log, method, patches.Finalizers, "Postfixes:"); } }
/* * Prefixes on SetupRequirement usually completely reroute the method. * So we need to remove those. Originally caused by ValheimPlus. * Might need tweaking if other mods use a SetupRequirement Prefix without * removing control completely. */ private static void RemoveAllPrefixesFrom_InventoryGui_SetupRequirement(Harmony harmony) { var invSetupReqRef = AccessTools.Method(typeof(InventoryGui), "SetupRequirement"); var patchInfo = Harmony.GetPatchInfo(invSetupReqRef); if (patchInfo == null) { return; } foreach (var prefix in patchInfo.Prefixes) { harmony.Unpatch(invSetupReqRef, HarmonyPatchType.Prefix, prefix.owner); } }
public static IEnumerable <MethodInfo> GetPatchMethods() { var patches = Harmony.GetAllPatchedMethods().ToList(); var filteredTranspilers = patches.Where(m => Harmony.GetPatchInfo(m).Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner))).ToList(); foreach (var filteredTranspiler in filteredTranspilers) { yield return(filteredTranspiler as MethodInfo); // Modbase.Harmony.Patch(AccessTools.Method(typeof(DynamicDrawManager), nameof(DynamicDrawManager.DrawDynamicThings)), prefix: new HarmonyMethod(typeof(H_DrawDynamicThings), "Prefix")); } // yield return AccessTools.Method(typeof(PawnRenderer), nameof(PawnRenderer.RenderPawnAt), new Type[] { typeof(Vector3), typeof(RotDrawMode), typeof(bool), typeof(bool) }); }
public void CheckDetour() { if (isFirstTime && Loader.HarmonyDetourInited) { isFirstTime = false; DebugLog.LogToFileOnly("ThreadingExtension.OnBeforeSimulationFrame: First frame detected. Checking detours."); //Caculate goverment salary RealCityEconomyExtension.CaculateGovermentSalary(); //reset playereducation fee RealCityEconomyExtension.RefreshPlayerEducationFee(); if (Loader.HarmonyDetourFailed) { string error = "RealCity HarmonyDetourInit is failed, Send RealCity.txt to Author."; DebugLog.LogToFileOnly(error); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Incompatibility Issue", error, true); } else { var harmony = new Harmony(HarmonyDetours.Id); var methods = harmony.GetPatchedMethods(); int i = 0; foreach (var method in methods) { var info = Harmony.GetPatchInfo(method); if (info.Owners?.Contains(HarmonyDetours.Id) == true) { DebugLog.LogToFileOnly($"Harmony patch method = {method.FullDescription()}"); if (info.Prefixes.Count != 0) { DebugLog.LogToFileOnly("Harmony patch method has PreFix"); } if (info.Postfixes.Count != 0) { DebugLog.LogToFileOnly("Harmony patch method has PostFix"); } i++; } } if (i != HarmonyPatchNum) { string error = $"RealCity HarmonyDetour Patch Num is {i}, Right Num is {HarmonyPatchNum} Send RealCity.txt to Author."; DebugLog.LogToFileOnly(error); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Incompatibility Issue", error, true); } } } }
public override bool IsApplicable(Game game) { if (Applied) { return(false); } var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo); if (AlreadyPatchedByOthers(patchInfo)) { return(false); } return(_IsApplicable(game)); }
/// <summary> /// Returns all patched methods by NPC Adventures mod. /// </summary> /// <returns>Enumerable patched methods</returns> public IEnumerable <PatchedMethod> GetPatchedMethods() { var methods = this.harmony .GetPatchedMethods() .ToArray(); foreach (var method in methods) { HarmonyLib.Patches info = Harmony.GetPatchInfo(method); if (info != null && info.Owners.Contains(this.harmony.Id)) { yield return(new PatchedMethod(method, info)); } } }
static void PatchMethod(Type type, string method) { if (type == null) { return; } var original = AccessTools.DeclaredMethod(type, method); var patches = Harmony.GetPatchInfo(original); if (patches == null) // Patch if it hasn't been patched. { Patching.ManualInstance("Factory").Patch(original, new HarmonyMethod(typeof(FactoryPatches), method)); } }
public static string GetStackTraceString(StackTrace st, out List <MethodMeta> methods) { var stringBuilder = new StringBuilder(255); methods = new List <MethodMeta>(); for (int i = 0; i < st.FrameCount; i++) { var method = Harmony.GetMethodFromStackframe(st.GetFrame(i)); if (method is MethodInfo replacement) { var original = Harmony.GetOriginalMethod(replacement); if (original != null) { method = original; } } GetStringForMethod(ref stringBuilder, method); if (method != null) { var p = Harmony.GetPatchInfo(method); if (p != null && p.Owners.Count != 0) { var pString = GetPatchStrings(method, p); if (pString != null) { stringBuilder.Append(pString); } } methods.Add(new MethodMeta(method, p)); } else { methods.Add(null); } stringBuilder.Append("\n"); } return(stringBuilder.ToString()); }
public void CheckDetour() { if (isFirstTime && Loader.DetourInited && Loader.HarmonyDetourInited) { isFirstTime = false; if (Loader.DetourInited) { DebugLog.LogToFileOnly("ThreadingExtension.OnBeforeSimulationFrame: First frame detected. Checking detours."); if (Loader.HarmonyDetourFailed) { string error = "MoreEffectiveTransfer HarmonyDetourInit is failed, Send MoreEffectiveTransfer.txt to Author."; DebugLog.LogToFileOnly(error); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Incompatibility Issue", error, true); } else { var harmony = new Harmony(HarmonyDetours.ID); var methods = harmony.GetPatchedMethods(); int i = 0; foreach (var method in methods) { var info = Harmony.GetPatchInfo(method); if (info.Owners?.Contains(harmony.Id) == true) { DebugLog.LogToFileOnly($"Harmony patch method = {method.FullDescription()}"); if (info.Prefixes.Count != 0) { DebugLog.LogToFileOnly("Harmony patch method has PreFix"); } if (info.Postfixes.Count != 0) { DebugLog.LogToFileOnly("Harmony patch method has PostFix"); } i++; } } if (i != HarmonyPatchNum) { string error = $"MoreEffectiveTransfer HarmonyDetour Patch Num is {i}, Right Num is {HarmonyPatchNum} Send MoreEffectiveTransfer.txt to Author."; DebugLog.LogToFileOnly(error); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Incompatibility Issue", error, true); } } } } }
public override bool IsApplicable(Game game) { var patchInfo = Harmony.GetPatchInfo(TargetMethodInfo); if (AlreadyPatchedByOthers(patchInfo)) { return(false); } if (CampaignData.NeutralFaction.DefaultPartyTemplate != null) { return(false); } var hash = TargetMethodInfo.MakeCilSignatureSha256(); return(hash.MatchesAnySha256(Hashes)); }
/// <summary> /// Checks to see if a Harmony Prefix patch is currently applied. /// </summary> public static bool IsPrefixInstalled(MethodInfo originalMethod) { var patches = Harmony.GetPatchInfo(originalMethod); if (patches != null) { foreach (var patch in patches.Prefixes) { if (patch.owner == harmonyID) { return(true); } } } return(false); }
/// <summary> /// Produces a human-readable list of Harmony patches on a given set of methods. /// </summary> public static string DescribePatchedMethodsList(IEnumerable <MethodBase> patchedMethods) { try { var methodList = patchedMethods.ToList(); // generate method name strings so we can sort the patches alphabetically var namedMethodList = new List <(string methodName, MethodBase method)>(methodList.Count); foreach (var method in methodList) { if (method == null) { continue; } var nestedName = GetNestedMemberName(method); namedMethodList.Add((nestedName, method)); } if (namedMethodList.Count == 0) { return("No patches have been reported."); } // sort patches by patched method name namedMethodList.Sort((m1, m2) => string.Compare(m1.methodName, m2.methodName, StringComparison.Ordinal)); var builder = new StringBuilder(); foreach (var(methodName, method) in namedMethodList) { // write patched method builder.Append(methodName); builder.Append(": "); // write patches var patches = Harmony.GetPatchInfo(method); if (HasActivePatches(patches)) { // write prefixes if (patches.Prefixes is { Count: > 0 }) { builder.Append("PRE: "); AppendPatchList(patches.Prefixes, builder); } // write postfixes if (patches.Postfixes is { Count: > 0 })