// ===================================================================== // Shared Utility Functions // ===================================================================== private static bool HigherTaxesModExists(HarmonyInstance harmonyInstance) { try { // Check if HigherTaxes exists by looking for specific patches. var Player_IncreaseTaxRate = typeof(Player).GetMethod("IncreaseTaxRate"); var Home_GetHappinessFromTax = typeof(Home).GetMethod("GetHappinessFromTax", BindingFlags.NonPublic | BindingFlags.Instance); bool Player_IncreaseTaxRate_patched = false; bool Home_GetHappinessFromTax_patched = false; // Check for patch that removes the 30% limit. var info = harmonyInstance.GetPatchInfo(Player_IncreaseTaxRate); if (info == null) { return(false); } foreach (var patch in info.Prefixes) { if (patch.owner == "cmjten10.HigherTaxes") { Player_IncreaseTaxRate_patched = true; break; } } if (!Player_IncreaseTaxRate_patched) { return(false); } // Check for patch that decreases happiness further past 30%. info = harmonyInstance.GetPatchInfo(Home_GetHappinessFromTax); if (info == null) { return(false); } foreach (var patch in info.Postfixes) { if (patch.owner == "cmjten10.HigherTaxes") { Home_GetHappinessFromTax_patched = true; break; } } return(Home_GetHappinessFromTax_patched); } catch { return(false); } }
private IEnumerable <Patch> GetSortedPatches(HarmonyInstance harmonyInstance, MethodBase method) { Patches patches = harmonyInstance.GetPatchInfo(method); return(patches.Prefixes.OrderByDescending(patch => patch.priority) .Concat(patches.Transpilers.OrderByDescending(patch => patch.priority)) .Concat(patches.Postfixes.OrderByDescending(patch => patch.priority))); }
/// <summary> /// Extension method to HarmonyInstance, used to record the state of patching when invoked /// </summary> /// <param name="harmonyInstance">An instance of HarmonyInstance</param> /// <param name="method">The method to audit</param> public static void AuditPatches(this HarmonyInstance harmonyInstance, MethodBase method) { if (!MethodPatches.TryGetValue(method, out var patchlist)) { patchlist = new List <PatchDatum>(); } patchlist.Add(new PatchDatum(harmonyInstance.GetPatchInfo(method))); MethodPatches[method] = patchlist; }
static void PostfixOnce(this HarmonyInstance instance, MethodInfo original, MethodInfo postfix) { var postfixes = instance.GetPatchInfo(original)?.Postfixes; if (postfixes == null || !postfixes.Any(patch => patch != null && patch.owner == _multiversionmodfix)) { instance.Patch(original, postfix: new HarmonyMethod(postfix)); } }
private static void ConditionalPatch(HarmonyInstance harmony, MethodBase method, HarmonyMethod prefix, HarmonyMethod postfix) { if (harmony.GetPatchInfo(method)?.Owners?.Contains(harmony.Id) == true) { #if DEBUG Debug.LogWarningFormat("TransferInfo: HarmonyPatches.ConditionalPatch - Harmony patches already present for {0}", string.Format("{0}.{1}", method.ReflectedType?.Name ?? "(null)", method.Name)); #endif return; } harmony.Patch(method, prefix, postfix); }
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) { HarmonyInstance harmonyInstance = HarmonyInstance.Create(modEntry.Info.Id); foreach (MethodBase method in harmonyInstance.GetPatchedMethods().ToList()) { Patches patchInfo = harmonyInstance.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().patch.DeclaringType.DeclaringType?.Name}.{method.DeclaringType.Name}.{method.Name}"); foreach (Patch patch in patches) { try { harmonyInstance.Unpatch(method, patch.patch); } catch (Exception e) { Error(e); } } } } Patched = false; } modEntry.OnSaveGUI -= HandleSaveGUI; Core = null; Settings = null; Version = null; _logger = null; process.Log("Disabled."); } }
private static void ConditionalPatch(this HarmonyInstance harmony, MethodBase method, HarmonyMethod prefix, HarmonyMethod postfix) { var fullMethodName = string.Format("{0}.{1}", method.ReflectedType?.Name ?? "(null)", method.Name); if (harmony.GetPatchInfo(method)?.Owners?.Contains(harmony.Id) == true) { Debug.LogWarningFormat("Harmony patches already present for {0}", fullMethodName); } else { Debug.LogFormat("Patching {0}...", fullMethodName); harmony.Patch(method, prefix, postfix); } }
static void FixPatches(HarmonyInstance harmony) { var original = typeof(CharacterBuildController).GetMethod("OnShow", BindingFlags.Instance | BindingFlags.NonPublic); if (original == null) { Log("Can't find method CharacterBuildController.OnShow"); return; } var info = harmony.GetPatchInfo(original); if (info == null) { Log("CharacterBuildController.OnShow is not patched!!!!"); return; } harmony.Unpatch(original, HarmonyPatchType.Prefix, "Respec"); }
private void RefreshListOfPatchOwners(string modId, bool reset = true) { if (reset || _modIdsToColor == null) { _modIdsToColor = new Dictionary <string, string>(); } HarmonyInstance harmonyInstance = HarmonyInstance.Create(modId); foreach (Patch patch in harmonyInstance.GetPatchedMethods().SelectMany(method => { Patches patches = harmonyInstance.GetPatchInfo(method); return(patches.Prefixes.Concat(patches.Transpilers).Concat(patches.Postfixes)); })) { if (!_modIdsToColor.ContainsKey(patch.owner)) { _modIdsToColor[patch.owner] = ColorUtility.ToHtmlStringRGBA(UnityEngine.Random.ColorHSV(0f, 1f, 0.25f, 1f, 0.75f, 1f)); } } }
private static void Unpatch(HarmonyInstance harmony, MethodBase b, string id, bool pre = true, bool post = true, bool trans = true, string onlyUnpatch = null) { //FileLog.Log($"checking to unpatch: {b.FullName()}"); Patches pa = harmony.GetPatchInfo(b); if (pa == null) { //FileLog.Log("no patch attached"); return; } if (pre) { UnpatchCheckList(harmony, b, id, pa.Prefixes, onlyUnpatch); } if (post) { UnpatchCheckList(harmony, b, id, pa.Postfixes, onlyUnpatch); } if (trans) { UnpatchCheckList(harmony, b, id, pa.Transpilers, onlyUnpatch); } }
public static bool Load(UnityModManager.ModEntry modEntry) { Main.Logger = modEntry.Logger; Main.settings = UnityModManager.ModSettings.Load <Main.Settings>(modEntry); HarmonyInstance harmonyInstance = HarmonyInstance.Create(modEntry.Info.Id); harmonyInstance.PatchAll(Assembly.GetExecutingAssembly()); MethodInfo method = typeof(ActorMenu).GetMethod("Awake", BindingFlags.Instance | BindingFlags.NonPublic); Patches patchInfo = harmonyInstance.GetPatchInfo(method); ReadOnlyCollection <Patch> readOnlyCollection = (patchInfo != null) ? patchInfo.Postfixes : null; if (readOnlyCollection == null || readOnlyCollection.Count == 0) { HarmonyMethod harmonyMethod = new HarmonyMethod(typeof(ActorMenu_Awake_Patch), "Postfix", new Type[] { typeof(ActorMenu) }); harmonyInstance.Patch(method, null, harmonyMethod, null); } modEntry.OnToggle = new Func <UnityModManager.ModEntry, bool, bool>(Main.OnToggle); modEntry.OnGUI = new Action <UnityModManager.ModEntry>(Main.OnGUI); modEntry.OnSaveGUI = new Action <UnityModManager.ModEntry>(Main.OnSaveGUI); return(true); }
/// <summary> /// Produces a human-readable list of all patched methods and their respective patches. /// </summary> /// <param name="instance">A HarmonyInstance that can be queried for patch information.</param> public static string DescribePatchedMethods(HarmonyInstance instance) { try { IEnumerable <MethodBase> patchedMethods; try { patchedMethods = instance.GetPatchedMethods(); } catch (Exception e) { return("Could not retrieve patched methods from the Harmony library:\n" + e); } var methodList = patchedMethods.ToList(); // generate method name strings so we can sort the patches alphabetically var namedMethodList = new List <NameMethodPair>(methodList.Count); foreach (var method in methodList) { if (method == null) { continue; } string methodName; if (method.DeclaringType != null) { methodName = string.Concat(method.DeclaringType.Name, ".", method.Name); } else { methodName = method.Name; } namedMethodList.Add(new NameMethodPair(methodName, 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 pair in namedMethodList) { // write patched method builder.Append(pair.MethodName); builder.Append(": "); // write patches var patches = instance.GetPatchInfo(pair.Method); if (HasActivePatches(patches)) { // write prefixes if (patches.Prefixes != null && patches.Prefixes.Count > 0) { builder.Append("PRE: "); AppendPatchList(patches.Prefixes, builder); } // write postfixes if (patches.Postfixes != null && patches.Postfixes.Count > 0) { EnsureEndsWithSpace(builder); builder.Append("post: "); AppendPatchList(patches.Postfixes, builder); } // write transpilers if (patches.Transpilers != null && patches.Transpilers.Count > 0) { EnsureEndsWithSpace(builder); builder.Append("TRANS: "); AppendPatchList(patches.Transpilers, builder); } } else { builder.Append("(no patches)"); } builder.AppendLine(); } return(builder.ToString()); } catch (Exception e) { return("An exception occurred while collating patch data:\n" + e); } }
public void Disable(UnityModManager.ModEntry modEntry, bool unpatch = false) { DateTime startTime = DateTime.Now; Debug($"[{DateTime.Now - startTime:ss':'ff}] Disabling."); // using try-catch to prevent the progression being disrupt by exceptions try { if (Enabled && _eventHandler != null) { Debug($"[{DateTime.Now - startTime:ss':'ff}] Raising events: 'OnDisable'"); foreach (IModEventHandler handler in _eventHandler) { handler.HandleModDisable(); } } } catch (Exception e) { Error(e.ToString()); } _eventHandler = null; if (unpatch) { HarmonyInstance harmonyInstance = HarmonyInstance.Create(modEntry.Info.Id); foreach (MethodBase method in harmonyInstance.GetPatchedMethods().ToList()) { Patches patchInfo = harmonyInstance.GetPatchInfo(method); List <Patch> patches = patchInfo.Transpilers.Concat(patchInfo.Postfixes).Concat(patchInfo.Prefixes) .Where(patch => patch.owner == modEntry.Info.Id).ToList(); if (patches.Any()) { Debug($"[{DateTime.Now - startTime:ss':'ff}] Unpatching: {patches.First().patch.DeclaringType.DeclaringType?.Name}.{method.DeclaringType.Name}.{method.Name}"); foreach (Patch patch in patches) { try { harmonyInstance.Unpatch(method, patch.patch); } catch (Exception e) { Error(e.ToString()); } } } } Patched = false; } modEntry.OnSaveGUI -= HandleSaveGUI; Mod = null; Settings = null; Enabled = false; Debug($"[{DateTime.Now - startTime:ss':'ff}] Disabled."); }
private static void addMethodToRemoveListIfPatchedByMe(MethodBase patchedMethod, List <MethodBase> methodsToRemove) { harmony.GetPatchInfo(patchedMethod).Owners.DoIf(isPatchedByMe, delegate { methodsToRemove.Add(patchedMethod); }); }