public static void Clicked(Profiler prof, ProfileLog log)
        {
            if (Input.GetKey(KeyCode.LeftControl))
            {
                if (log.Meth == null)
                {
                    Messages.Message("Null method", MessageTypeDefOf.NegativeEvent, false);
                    return;
                }

                var patches = Harmony.GetAllPatchedMethods().ToList();
                // Patches patchInfo = Harmony.GetPatchInfo(log.Meth);

                foreach (var methodBase in patches)
                {
                    var infos = Harmony.GetPatchInfo(methodBase);
                    foreach (var infosPrefix in infos.Prefixes)
                    {
                        if (infosPrefix.PatchMethod == log.Meth)
                        {
                            Analyzer.harmony.Unpatch(methodBase, HarmonyPatchType.All, "*");
                            Messages.Message("Unpatched prefixes", MessageTypeDefOf.TaskCompletion, false);
                        }
                    }
                    foreach (var infosPostfixesx in infos.Postfixes)
                    {
                        if (infosPostfixesx.PatchMethod == log.Meth)
                        {
                            Analyzer.harmony.Unpatch(methodBase, HarmonyPatchType.All, "*");
                            Messages.Message("Unpatched postfixes", MessageTypeDefOf.TaskCompletion, false);
                        }
                    }
                }
            }
        }
示例#2
0
        private void RefreshListOfPatchOwners(string modId, bool reset = true)
        {
            if (reset || _modIdsToColor == null)
            {
                _modIdsToColor = new Dictionary <string, string>();
            }
            var patches = Harmony.GetAllPatchedMethods().SelectMany(method => {
                Patches patchInfo = Harmony.GetPatchInfo(method);
                return(patchInfo.Prefixes.Concat(patchInfo.Transpilers).Concat(patchInfo.Postfixes));
            });
            var   owners = patches.Select(patchInfo => patchInfo.owner).Distinct().OrderBy(owner => owner);
            float hue    = 0.0f;

            foreach (var owner in owners)
            {
                if (!_modIdsToColor.ContainsKey(owner))
                {
                    var color = UnityEngine.Random.ColorHSV(
                        hue, hue,
                        0.25f, .75f,
                        0.75f, 1f
                        );
                    _modIdsToColor[owner] = ColorUtility.ToHtmlStringRGBA(color);
                    hue = (hue + 0.1f) % 1.0f;
                }
            }
        }
        public static void ProfilePatch()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            var filteredTranspilers = patches
                                      .Where(m => Harmony.GetPatchInfo(m).Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner) && !TranspilerMethodUtility.PatchedMeths.Contains(m)))
                                      .ToList();

            TranspilerMethodUtility.PatchedMeths.AddRange(filteredTranspilers);

            foreach (var meth in filteredTranspilers)
            {
                try
                {
                    Modbase.Harmony.Patch(meth, transpiler: TranspilerMethodUtility.TranspilerProfiler);
                }
                catch (Exception e)
                {
#if DEBUG
                    ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}");
#endif
#if NDEBUG
                    if (Settings.verboseLogging)
                    {
                        ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}");
                    }
#endif
                }
            }
        }
示例#4
0
        private void RefreshListOfPatchOwners(string modId, bool reset = true)
        {
            if (reset || _modIdsToColor == null)
            {
                _modIdsToColor = new Dictionary <string, string>();
            }

            var rgbaValues = Enum.GetValues(typeof(RGBA));
            var rgbaCount  = rgbaValues.Length;

            foreach (Patch patch in Harmony.GetAllPatchedMethods().SelectMany(method => {
                Patches patches = Harmony.GetPatchInfo(method);
                return(patches.Prefixes.Concat(patches.Transpilers).Concat(patches.Postfixes));
            }))
            {
                if (!_modIdsToColor.ContainsKey(patch.owner))
                {
                    var  rgbaIndex   = Math.Abs(patch.owner.GetHashCode() % rgbaCount);
                    RGBA color       = (RGBA)rgbaValues.GetValue(rgbaIndex);
                    var  colorString = color.ToHtmlString();
                    _modIdsToColor[patch.owner] = colorString;

                    //_modIdsToColor[patch.owner] = ColorUtility.ToHtmlStringRGBA(UnityEngine.Random.ColorHSV(0f, 1f, 0.25f, 1f, 0.75f, 1f));
                }
            }
        }
 private static void UnpatchMethodFull(MethodInfo method, bool display = true)
 {
     foreach (var methodBase in Harmony.GetAllPatchedMethods())
     {
         var infos = Harmony.GetPatchInfo(methodBase);
         foreach (var infosPrefix in infos.Prefixes)
         {
             if (infosPrefix.PatchMethod == method)
             {
                 Analyzer.harmony.Unpatch(methodBase, method);
                 return;
             }
         }
         foreach (var infosPostfixesx in infos.Postfixes)
         {
             if (infosPostfixesx.PatchMethod == method)
             {
                 Analyzer.harmony.Unpatch(methodBase, method);
                 return;
             }
         }
     }
     if (display)
     {
         Warn("Failed to locate method to unpatch");
     }
 }
        public static void ProfilePatch()
        {
            var go    = new HarmonyMethod(typeof(H_HarmonyTranspilers), nameof(Prefix));
            var biff  = new HarmonyMethod(typeof(H_HarmonyTranspilers), nameof(Postfix));
            var trans = new HarmonyMethod(typeof(H_HarmonyTranspilers), nameof(Transpiler));

            int c       = 0;
            int p       = 0;
            var patches = Harmony.GetAllPatchedMethods().ToList();

            foreach (var mode in patches)
            {
                try
                {
                    c++;

                    Patches patchInfo = Harmony.GetPatchInfo(mode);
                    var     pilers    = patchInfo.Transpilers;
                    if (!pilers.NullOrEmpty())
                    {
                        p++;

                        if (pilers.Any(x => x.owner != Analyzer.harmony.Id && x.owner != Analyzer.perfharmony.Id) && !PatchedMeths.Contains(mode))
                        {
                            PatchedMeths.Add(mode);
                            Analyzer.harmony.Patch(mode, go, biff);
                        }
                    }
                }
                catch (Exception)
                {
                }
            }
        }
        public static void ProfilePatch()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            var filteredTranspilers = patches
                                      .Where(m => Harmony.GetPatchInfo(m).Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner) && !TranspilerMethodUtility.PatchedMeths.Contains(m)))
                                      .ToList();

            TranspilerMethodUtility.PatchedMeths.AddRange(filteredTranspilers);

            foreach (var meth in filteredTranspilers)
            {
                try
                {
                    Modbase.Harmony.Patch(meth, transpiler: TranspilerMethodUtility.TranspilerProfiler);
                }
                catch (Exception e)
                {
#if DEBUG
                    ThreadSafeLogger.Error($"[Analyzer] Failed to patch transpiler, failed with the message {e.Message}");
#endif
#if NDEBUG
                    if (Settings.verboseLogging)
                    {
                        ThreadSafeLogger.Error($"[Analyzer] Failed to patch transpiler {meth.DeclaringType.FullName + ":" + meth.Name}, failed with the message {e.Message}");
                    }
#endif
                }
            }
        }
        public static bool HarmonyInstance_GetPatchedMethods_Prefix(string ___id, out IEnumerable <MethodBase> __result)
        {
#if DEBUG
            UnityEngine.Debug.Log($"GetPatchedMethods (HarmonyId: {___id})");
#endif
            __result = Harmony.GetAllPatchedMethods();
            return(false);
        }
示例#9
0
 private void RefreshPatchInfoOfAllMods(string modId)
 {
     _patches = new Dictionary <MethodBase, List <Patch> >();
     foreach (MethodBase method in Harmony.GetAllPatchedMethods())
     {
         _patches.Add(method, GetSortedPatches(method).ToList());
     }
 }
示例#10
0
 /// <summary>
 /// Produces a human-readable list of all methods patched by all Harmony instances and their respective patches.
 /// </summary>
 public static string DescribeAllPatchedMethods()
 {
     try {
         return(DescribePatchedMethodsList(Harmony.GetAllPatchedMethods()));
     } catch (Exception e) {
         return("Could not retrieve patched methods from the Harmony library:\n" + e);
     }
 }
示例#11
0
 private static IEnumerable <(string owner, IEnumerable <MethodBase> methods)> EnumerateObsoleteMethodPatchOwners()
 {
     return(Harmony.GetAllPatchedMethods()
            .Select(method => (method, info: Harmony.GetPatchInfo(method)))
            .Where(pair => HasActivePatches(pair.info) && pair.method.HasAttribute <ObsoleteAttribute>())
            .SelectMany(pair => pair.info.Owners, (pair, owner) => (owner, pair.method))
            .GroupBy(pair => pair.owner, pair => pair.method)
            .Select(grp => (grp.Key, grp as IEnumerable <MethodBase>)));
 }
示例#12
0
    internal static void Reenable()
    {
        if (!Config.Extras.HarmonyInlining)
        {
            return;
        }

        _ = Parallel.ForEach(Harmony.GetAllPatchedMethods(), EnableInlining);
    }
示例#13
0
        /// <summary>
        /// Get collection [method, patches]
        /// </summary>
        /// <param name="owners">filter patches by owners or null for get all patches</param>
        /// <param name="skipGenericMethods">include generic methods</param>
        /// <returns></returns>
        public static Dictionary <MethodBase, Patches> GetPatches(string[] owners, bool skipGenericMethods)
        {
            var patches = Harmony.GetAllPatchedMethods()
                          .Where(method => !skipGenericMethods || !method.DeclaringType.IsGenericType)
                          .Select(method => new { method, patches = Harmony.GetPatchInfo(method) });

            return(owners == null
                ? patches.ToDictionary(x => x.method, y => y.patches)
                : patches.Where(patch => patch.patches.Owners.Any(x => owners.Any(x.Equals)))
                   .ToDictionary(x => x.method, y => y.patches));
        }
示例#14
0
 public static unsafe void PrintInlined()
 {
     foreach (var m in Harmony.GetAllPatchedMethods())
     {
         // method->inline_info
         if ((*(byte *)(m.MethodHandle.Value + 32) & 1) == 1)
         {
             Log.Warning($"Mono inlined {m.FullDescription()} {*(byte*)(m.MethodHandle.Value + 32) & 1} {*((ushort*)(m.MethodHandle.Value) + 1) & (ushort)MethodImplOptions.NoInlining}");
         }
     }
 }
示例#15
0
 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 static void CheckAndApplyCleaveCompatibility()
        {
            var methodBases = Harmony.GetAllPatchedMethods();

            foreach (var method in methodBases)
            {
                if (Harmony.GetPatchInfo(method).Owners.Contains("xorberax.cutthrougheveryone"))
                {
                    ApplyCompatibility();
                }
            }
        }
示例#17
0
        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);
        }
示例#18
0
 private void RefreshPatchInfoOfPotentialConflict(string modId)
 {
     _patches = new Dictionary <MethodBase, List <Patch> >();
     foreach (MethodBase method in Harmony.GetAllPatchedMethods())
     {
         IEnumerable <Patch> patches = GetSortedPatches(method);
         var owners = patches.Select(patch => patch.owner).Distinct().ToHashSet();
         if (owners.Count > 1 && (_modID == null || owners.Contains(_modID)))
         {
             _patches.Add(method, patches.ToList());
         }
     }
 }
示例#19
0
 private void RefreshPatchInfoOfSelected(string modId)
 {
     _patches = new Dictionary <MethodBase, List <Patch> >();
     foreach (MethodBase method in Harmony.GetAllPatchedMethods())
     {
         IEnumerable <Patch> patches =
             GetSortedPatches(method).Where(patch => patch.owner == _modID);
         if (patches.Any())
         {
             _patches.Add(method, patches.ToList());
         }
     }
 }
        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) });
        }
示例#21
0
        private void RefreshPatchInfoOfPotentialConflict(string modId)
        {
            _patches = new Dictionary <MethodBase, List <Patch> >();
            Harmony harmonyInstance = new Harmony(_modId);

            foreach (MethodBase method in Harmony.GetAllPatchedMethods())
            {
                IEnumerable <Patch> patches = GetSortedPatches(harmonyInstance, method);
                if (patches.Any(patch => patch.owner == _modId) && patches.Any(patch => patch.owner != _modId))
                {
                    _patches.Add(method, patches.ToList());
                }
            }
        }
示例#22
0
        public static HashSet <string> GetAllHarmonyInstances()
        {
            HashSet <string> owners = new HashSet <string>();
            var patched             = Harmony.GetAllPatchedMethods();

            foreach (var method in patched)
            {
                var patchInfo = Harmony.GetPatchInfo(method);
                foreach (var owner in patchInfo.Owners)
                {
                    if (!owner.Equals(Id))
                    {
                        owners.Add(owner);
                    }
                }
            }
            return(owners);
        }
        public static void CheckForShoulderCam()
        {
            if (CamCompatibilityCheckComplete == false)
            {
                CamCompatibilityCheckComplete = false;
                var methodBases = Harmony.GetAllPatchedMethods();

                foreach (var method in methodBases)
                {
                    if (Harmony.GetPatchInfo(method).Owners.Contains("xorberax.shouldercam"))
                    {
                        XorbShoulderCamDetected = true;
                    }
                }

                CamCompatibilityCheckComplete = true;
            }
        }
        public static void UnpatchMethod(MethodInfo method)
        {
            foreach (MethodBase methodBase in Harmony.GetAllPatchedMethods())
            {
                HarmonyLib.Patches infos = Harmony.GetPatchInfo(methodBase);

                var allPatches = infos.Prefixes.Concat(infos.Postfixes, infos.Transpilers, infos.Finalizers);

                if (!allPatches.Any(patch => patch.PatchMethod == method))
                {
                    continue;
                }

                Modbase.Harmony.Unpatch(methodBase, method);
                return;
            }

            Warn("Failed to locate method to unpatch");
        }
示例#25
0
        private void RefreshListOfPatchOwners(string modId, bool reset = true)
        {
            if (reset || _modIdsToColor == null)
            {
                _modIdsToColor = new Dictionary <string, string>();
            }


            foreach (Patch patch in Harmony.GetAllPatchedMethods().SelectMany(method =>
            {
                Patches patches = Harmony.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));
                }
            }
        }
示例#26
0
        public static void CheckHarmonyPatchesForPotentialWarnings()
        {
            IEnumerable <(MethodBase, HarmonyLib.Patches)> patchList = Harmony.GetAllPatchedMethods().Select(mb => (mb, Harmony.GetPatchInfo(mb))).Where(mp => HasActivePatches(mp.Item2));
            StringBuilder builderObsolete = new StringBuilder($"Potentially outdated mods for {typeof(Log).Assembly.GetName().Version}. Please alert the mod authors of the mods in the following list that they may have to update the patches for their mods and include the following information.\n");

            bool printObsolete = false;

            foreach (IGrouping <string, (string owner, MethodBase)> owners in patchList.Where(mp => mp.Item1.HasAttribute <ObsoleteAttribute>())
                     .SelectMany(mp => mp.Item2.Prefixes.Concat(mp.Item2.Postfixes).Concat(mp.Item2.Transpilers)
                                 .Select(p => (p.owner, mp.Item1))).GroupBy(p => p.owner))
            {
                builderObsolete.AppendLine($"Mod: {owners.Key}: {string.Join(" | ", owners.Select(mb => mb.Item2.Name).Distinct())}");
                printObsolete = true;
            }

            if (printObsolete)
            {
                HugsLibController.Logger.Error(builderObsolete.ToString());
            }
        }
示例#27
0
        /// <summary>
        /// Compiles the patched method list from Harmony.
        /// </summary>
        internal static void CompileModPatches()
        {
            var mods = Global.Instance.modManager?.mods;

            if (mods != null)
            {
                var methodsByID = new Dictionary <string, LoadedModData>();
                // Index the mods list by Harmony ID
                foreach (var mod in mods)
                {
                    var data = mod.loaded_mod_data;
                    var h    = data?.harmony;
                    if (h != null)
                    {
                        // Remove anything that was loaded before us
                        data.patched_methods?.Clear();
                        data.patched_methods = new HashSet <MethodBase>();
                        if (h != null && !string.IsNullOrEmpty(h.Id))
                        {
                            methodsByID[h.Id] = data;
                        }
                    }
                }
                // Match up all patched methods to the mod itself
                foreach (var method in Harmony.GetAllPatchedMethods())
                {
                    var patchInfo = Harmony.GetPatchInfo(method);
                    var owners    = patchInfo?.Owners;
                    if (owners != null)
                    {
                        foreach (string owner in owners)
                        {
                            if (methodsByID.TryGetValue(owner, out LoadedModData data))
                            {
                                data.patched_methods.Add(method);
                            }
                        }
                    }
                }
            }
        }
        public static void ProfilePatch()
        {
            var go      = new HarmonyMethod(typeof(H_HarmonyPatches), nameof(Prefix));
            var biff    = new HarmonyMethod(typeof(H_HarmonyPatches), nameof(Postfix));
            var patches = Harmony.GetAllPatchedMethods().ToList();

            foreach (var mode in patches)
            {
                Patches patchInfo = Harmony.GetPatchInfo(mode);
                foreach (var fix in patchInfo.Prefixes)
                {
                    try
                    {
                        if (Analyzer.harmony.Id != fix.owner && Analyzer.perfharmony.Id != fix.owner && !PatchedPres.Contains(fix))
                        {
                            PatchedPres.Add(fix);
                            Analyzer.harmony.Patch(fix.PatchMethod, go, biff);
                        }
                    }
                    catch (Exception)
                    {
                    }
                }

                foreach (var fix in patchInfo.Postfixes)
                {
                    try
                    {
                        if (Analyzer.harmony.Id != fix.owner && Analyzer.perfharmony.Id != fix.owner && !PatchedPosts.Contains(fix))
                        {
                            PatchedPosts.Add(fix);
                            Analyzer.harmony.Patch(fix.PatchMethod, go, biff);
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            }
        }
示例#29
0
        public static IEnumerable <MethodInfo> GetPatchMethods()
        {
            var patches = Harmony.GetAllPatchedMethods().ToList();

            foreach (var patch in patches)
            {
                HarmonyLib.Patches p = null;
                try
                {
                    p = Harmony.GetPatchInfo(patch);
                }
                catch (Exception e)
                {
                    ThreadSafeLogger.ReportException(e, $"Failed to get patch info for {Utility.GetSignature(patch)}");
                    continue;
                }

                if (patch is MethodInfo info && p.Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner)))
                {
                    yield return(info);
                }
            }
        }
示例#30
0
        static void Main_Example()
        {
            // <create>
            var harmony = new Harmony("com.company.project.product");

            // </create>

            // <debug>
            Harmony.DEBUG = true;
            // </debug>

            // <log>
            FileLog.Log("something");
            // or buffered:
            FileLog.LogBuffered("A");
            FileLog.LogBuffered("B");
            FileLog.FlushBuffer();             /* don't forget to flush */
            // </log>

            // <patch_annotation>
            var assembly = Assembly.GetExecutingAssembly();

            harmony.PatchAll(assembly);

            // or implying current assembly:
            harmony.PatchAll();
            // </patch_annotation>

            void PatchManual()
            {
                // <patch_manual>
                // add null checks to the following lines, they are omitted for clarity
                var original = typeof(TheClass).GetMethod("TheMethod");
                var prefix   = typeof(MyPatchClass1).GetMethod("SomeMethod");
                var postfix  = typeof(MyPatchClass2).GetMethod("SomeMethod");

                harmony.Patch(original, new HarmonyMethod(prefix), new HarmonyMethod(postfix));

                // You can use named arguments to specify certain patch types only:
                harmony.Patch(original, postfix: new HarmonyMethod(postfix));
                harmony.Patch(original, prefix: new HarmonyMethod(prefix), transpiler: new HarmonyMethod(transpiler));
                // </patch_manual>

                // <patch_method>
                var harmonyPostfix = new HarmonyMethod(postfix)
                {
                    priority = Priority.Low,
                    before   = new[] { "that.other.harmony.user" }
                };
                // </patch_method>
            }

            PatchManual();

            // <patch_getall>
            var originalMethods = Harmony.GetAllPatchedMethods();

            foreach (var method in originalMethods)
            {
            }
            // </patch_getall>

            // <patch_get>
            var myOriginalMethods = harmony.GetPatchedMethods();

            foreach (var method in myOriginalMethods)
            {
            }
            // </patch_get>

            void PatchInfo()
            {
                // <patch_info>
                // get the MethodBase of the original
                var original = typeof(TheClass).GetMethod("TheMethod");

                // retrieve all patches
                var patches = Harmony.GetPatchInfo(original);

                if (patches is null)
                {
                    return;                                  // not patched
                }
                // get a summary of all different Harmony ids involved
                FileLog.Log("all owners: " + patches.Owners);

                // get info about all Prefixes/Postfixes/Transpilers
                foreach (var patch in patches.Prefixes)
                {
                    FileLog.Log("index: " + patch.index);
                    FileLog.Log("owner: " + patch.owner);
                    FileLog.Log("patch method: " + patch.PatchMethod);
                    FileLog.Log("priority: " + patch.priority);
                    FileLog.Log("before: " + patch.before);
                    FileLog.Log("after: " + patch.after);
                }
                // </patch_info>
            }

            PatchInfo();

            // <patch_has>
            if (Harmony.HasAnyPatches("their.harmony.id"))
            {
            }
            // </patch_has>

            // <version>
            var dict = Harmony.VersionInfo(out var myVersion);

            FileLog.Log("My version: " + myVersion);
            foreach (var entry in dict)
            {
                var id      = entry.Key;
                var version = entry.Value;
                FileLog.Log("Mod " + id + " uses Harmony version " + version);
            }
            // </version>
        }