public static void ProfileHarmonyPatches(string[] owners, bool skipGenericMethods, bool skipTranspiledMethods)
        {
            PatchHandler.StopCollectData();
            int transpilersSkip        = 0;
            int patchedCount           = 0;
            var patchedMethodsByOwners = HarmonyMain.GetPatchedMethods(owners, skipGenericMethods);

            foreach (var patchInfo in patchedMethodsByOwners)
            {
                bool   isTranspiler = patchInfo.patchType == PatchType.Transpiler;
                string patchOwner   = patchInfo.harmonyPatch.owner;
                var    patchMethod  = isTranspiler ? patchInfo.originalMethod : patchInfo.harmonyPatch.PatchMethod;

                if (skipTranspiledMethods && isTranspiler)
                {
                    Logger.Add($"Skip transpiled: [{patchOwner}] {patchMethod.GetMethodFullString()}");
                    transpilersSkip++;
                    continue;
                }

                if (TryAddProfiler(patchMethod))
                {
                    Logger.Add($"Patch: [{patchOwner}] {patchMethod.GetMethodFullString()}");
                    patchedCount++;
                }
                //else Logger.Add($"Already patched: [{patchOwner}] {patchMethod.GetMethodFullString()}");
            }
            PatchHandler.StartCollectData();
            Log.Warning($"Patched methods: {patchedCount}");
            if (transpilersSkip > 0)
            {
                Log.Warning($"Skip transpiled methods: {transpilersSkip}");
            }
        }
        public static void UnpatchByRule(float avgTimeLessThan, int ticksMoreThan)
        {
            var records = PatchHandler.GetProfileRecordsSorted().Where(x => x.IsValid && x.AvgTime <= avgTimeLessThan && x.TicksNum >= ticksMoreThan).Select(x => x.Method);

            PatchHandler.StopCollectData();
            int unpatched = 0;

            foreach (var methodBase in records)
            {
                try
                {
                    HarmonyMain.Instance.Unpatch(methodBase, HarmonyPatchType.All, HarmonyMain.Id);
                    Logger.Add($"Unpatched: {methodBase.GetMethodFullString()}");
                    PatchedMethods.Remove(methodBase);
                    PatchHandler.RemoveProfiledRecords(methodBase);
                    unpatched++;
                }
                catch (Exception e)
                {
                    Logger.Add($"[ERROR][UnpatchByRule] Exception: {e.Message}; method => {methodBase.GetMethodFullString()}");
                    Log.Error($"[ERROR][UnpatchByRule] Exception: {e.Message}; method => {methodBase.GetMethodFullString()}");
                }
            }

            if (unpatched > 0)
            {
                Log.Warning($"Unpatched methods by rule: {unpatched}");
            }

            if (PatchedMethods.Count > 0)
            {
                PatchHandler.StartCollectData();
            }
        }
 public static void UnpatchAll()
 {
     //Harmony.UnpatchAll(HarmonyBrowserId);
     foreach (var methodBase in PatchedMethods)
     {
         try
         {
             if (Settings.Get().debug)
             {
                 Log.Error($"[UnpatchAll] Try unpatch method => {methodBase.GetMethodFullString()}");
             }
             HarmonyMain.Instance.Unpatch(methodBase, HarmonyPatchType.All, HarmonyMain.Id);
             Logger.Add($"Unpatched: {methodBase.GetMethodFullString()}");
         }
         catch (Exception e)
         {
             Logger.Add($"[ERROR][UnpatchAll] Exception: {e.Message}; method => {methodBase.GetMethodFullString()}");
             Log.Error($"[ERROR][UnpatchAll] Exception: {e.Message}; method => {methodBase.GetMethodFullString()}");
         }
     }
     Log.Warning($"Unpatched methods: {PatchedMethods.Count}");
     PatchHandler.Reset();
     PatchHandler.StopCollectData();
     PatchedMethods.Clear();
 }
        public static void UnpatchInstances(string[] owners)
        {
            PatchHandler.StopCollectData();
            int unpatchedCount         = 0;
            var patchedMethodsByOwners = HarmonyMain.GetPatchedMethods(owners, false);

            foreach (var patchInfo in patchedMethodsByOwners)
            {
                var patchOwner     = patchInfo.harmonyPatch.owner;
                var originalMethod = patchInfo.originalMethod;
                HarmonyMain.Instance.Unpatch(originalMethod, HarmonyPatchType.All, patchOwner);
                Logger.Add($"Unpatched: {originalMethod.GetMethodFullString()}; Instance: {patchOwner}");
                unpatchedCount++;
            }
            if (PatchedMethods.Count > 0)
            {
                PatchHandler.StartCollectData();
            }
        }
        public static void UnpatchMethod(MethodBase m)
        {
            PatchHandler.StopCollectData();

            try
            {
                HarmonyMain.Instance.Unpatch(m, HarmonyPatchType.All, HarmonyMain.Id);
                Log.Warning($"Unpatched: {m.GetMethodFullString()}");
                PatchedMethods.Remove(m);
                PatchHandler.RemoveProfiledRecords(m);
            }
            catch (Exception e)
            {
                Log.Error($"[ERROR][UnpatchMethod] Exception: {e.Message}; method => {m.GetMethodFullString()}");
            }

            if (PatchedMethods.Count > 0)
            {
                PatchHandler.StartCollectData();
            }
        }
        public static void ProfileMethods(string[] methodNames)
        {
            TypeByName.Initialize();
            PatchHandler.StopCollectData();
            int patchedCount = 0;

            foreach (var methodName in methodNames)
            {
                if (methodName.StartsWith("UnityEngine."))
                {
                    continue; // skip in 1.2 hooking UE submodules
                }
                //var method = AccessTools.Method(methodName); // TODO: overloaded functions
                foreach (var method in GetAllMethodsWithOverloads(methodName))
                {
                    if (method == null)
                    {
                        Logger.Add($"[ERROR] Can't patch: {methodName}");
                        Log.Error($"[ERROR] Can't patch: {methodName}");
                        continue;
                    }

                    if (TryAddProfiler(method))
                    {
                        Logger.Add($"Patched: {method.GetMethodFullString()} asm: {method.Module.Assembly.GetName().Name}");
                        patchedCount++;
                    }
                    //else
                    //{
                    //    Logger.Add($"Already patched: {methodName}");
                    //}
                }
            }
            Log.Warning($"Patched methods: {patchedCount}");
            TypeByName.Close();
            PatchHandler.StartCollectData();
        }