コード例 #1
0
        private void DrawInstanceProfiler(Listing_Extended lister, Settings settings)
        {
            lister.LabelColored("Profile Harmony Instances", TitleLabelColor);
            Rect buttonRect1 = lister.GetRect(Text.LineHeight),
                 buttonRect2 = buttonRect1,
                 buttonRect3 = buttonRect1;

            buttonRect2.width = buttonRect3.width = buttonRect1.width = buttonRect1.width / 3;
            buttonRect2.x     = buttonRect1.xMax;
            buttonRect3.x     = buttonRect2.xMax;

            if (Widgets.ButtonText(buttonRect1, "Get instances"))
            {
                settings.profileInstances = String.Join("\n", HarmonyMain.GetAllHarmonyInstances().ToArray());
            }
            if (!settings.profileInstances.IsNullOrEmpty())
            {
                lister.CheckboxLabeled("Allow transpiled methods(slow patching)", ref settings.allowTranspiledMethods);
                if (Widgets.ButtonText(buttonRect2, $"Profile instances"))
                {
                    PatchHandler.Initialize();
                    var instances = settings.profileInstances.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
                    Profiler.Logger.LogOperation("PatchesProfiling", () => Patcher.ProfileHarmonyPatches(instances, true, !settings.allowTranspiledMethods));
                }
                if (Widgets.ButtonText(buttonRect3, "Unpatch instances"))
                {
                    var instances = settings.profileInstances.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
                    Profiler.Logger.LogOperation("UnpatchInstances", () => Patcher.UnpatchInstances(instances));
                }
            }
            settings.profileInstances = lister.TextAreaFocusControl("InstancesProfilerField", settings.profileInstances, 5, ref instancesScrollPos);
            lister.Gap(20f);
        }
コード例 #2
0
        private void DrawModsProfiler(Listing_Extended lister, Settings settings)
        {
            lister.LabelColored("Profile Mods", TitleLabelColor);

            Rect buttonRect1 = lister.GetRect(Text.LineHeight),
                 buttonRect2 = buttonRect1;

            buttonRect2.width = buttonRect1.width /= 2;
            buttonRect2.x     = buttonRect1.xMax;

            if (Widgets.ButtonText(buttonRect1, "Get mods"))
            {
                settings.profileMods = String.Join("\n", LoadedModManager.RunningModsListForReading.Select(x => Path.GetFileName(x.RootDir)).ToArray());
            }
            if (!settings.profileMods.IsNullOrEmpty())
            {
                lister.CheckboxLabeled("Allow Core assembly", ref settings.allowCoreAsm);
                if (Widgets.ButtonText(buttonRect2, $"Profile mods"))
                {
                    PatchHandler.Initialize();
                    var mods = settings.profileMods.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
                    Profiler.Logger.LogOperation("ModsProfiling", () => Patcher.ProfileMods(mods.ToList()));
                }
            }
            settings.profileMods = lister.TextAreaFocusControl("ModsProfilerField", settings.profileMods, 5, ref modsScrollPos);
            lister.Gap(20f);
        }
コード例 #3
0
        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();
            }
        }
コード例 #4
0
        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}");
            }
        }
コード例 #5
0
 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();
 }
コード例 #6
0
 private static void HarmonyPatch()
 {
     try
     {
         var patchHandler = new PatchHandler();
         patchHandler.PatchMethods();
     }
     catch (Exception e)
     {
         Log.Error($"PatchError: {e}");
     }
 }
コード例 #7
0
        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();
            }
        }
コード例 #8
0
        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();
            }
        }
コード例 #9
0
        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();
        }
コード例 #10
0
        /// <summary>
        /// Search the target byte array for an 8-byte magic value, then rewrite the string prefixed
        /// by the magic value. Strings are terminated by '\0', '.', '>', or '+'. This is very aggressive
        /// and has nothing to do with the PE format, so the magic value should be very unique!
        /// </summary>
        static unsafe void Patch(byte [] target, byte [] magicBytes, PatchHandler patchHandler)
        {
            if (magicBytes.Length != 8)
                throw new ArgumentException("must be exactly 8 bytes in length", nameof(magicBytes));

            fixed(byte *magicPtr = &magicBytes[0])
            fixed(byte *targetPtr = &target [0])
            {
                var magic = *(ulong *)magicPtr;

                for (var i = 0; i < target.Length - 8;)
                {
                    var patchAddr = (ulong *)(targetPtr + i);
                    if (*patchAddr != magic)
                    {
                        i++;
                    }
                    else
                    {
                        var length = 8;
                        while (true)
                        {
                            var b = target [i + length];
                            if (b == 0 || b == '.' || b == '>' || b == '+')
                            {
                                break;
                            }
                            length++;
                        }

                        patchHandler(targetPtr + i, length);
                        i += length;
                    }
                }
            }
        }
コード例 #11
0
        private void DrawProfilerTop15(Listing_Extended lister, Settings settings)
        {
            lister.LabelColored($"Top 15 (Triggered:{PatchHandler.ProfiledRecordsCount()} Methods:{Patcher.PatchedMethodsCount()})", TitleLabelColor);

            int maxRecordCount = 15;

            // update cache every 1 sec and skip update if mouse on buttons
            if (cached == null || !stopUpdate && cacheUpdateTimer.ElapsedMilliseconds > 1000L)
            {
                cached = PatchHandler.GetProfileRecordsSorted()
                         .Where(x => !hided.Any(x.MethodName.Equals))
                         //.OrderByDescending(x => x.TimeSpent)
                         .Take(maxRecordCount)
                         .ToList();
                cacheUpdateTimer = Stopwatch.StartNew();
            }

            // draw cached info
            stopUpdate = false;
            var backFont = Text.Font;

            foreach (var r in cached)
            {
                string tooltip = r.Tooltip;

                Rect buttonRect1 = lister.GetRect(Text.LineHeight),
                     buttonRect2 = buttonRect1,
                     buttonRect3 = buttonRect1,
                     buttonRect4 = buttonRect1,
                     buttonRect5 = buttonRect1;

                buttonRect1.width = buttonRect2.width = buttonRect3.width = buttonRect4.width = 40;

                buttonRect2.x = buttonRect1.xMax;
                buttonRect3.x = buttonRect2.xMax;
                buttonRect4.x = buttonRect3.xMax;

                buttonRect5.width -= 40 * 4;
                buttonRect5.x      = buttonRect4.xMax;

                if (ButtonText(buttonRect1, "Copy", tooltip + "\nPress for copy this method name", out bool button1IsMouseOver))
                {
                    if (!settings.profileCustom.Contains(r.MethodName))
                    {
                        bool addLine = !settings.profileCustom.IsNullOrEmptyOrEqual(Settings.CustomExampleStr);
                        if (addLine)
                        {
                            settings.profileCustom += $"\n{r.MethodName}";
                        }
                        else
                        {
                            settings.profileCustom = $"{r.MethodName}";
                        }
                    }
                }

                bool logActive = PatchHandler.logMethod != null && r.Method == PatchHandler.logMethod;
                if (ButtonText(buttonRect2, logActive ? "X" : "Log", tooltip + "\nPress for copy this method name", out bool button2IsMouseOver))
                {
                    // disable log this method
                    if (logActive)
                    {
                        PatchHandler.logMethod = null;
                    }
                    // enable log this method
                    else
                    {
                        PatchHandler.logMethod = r.Method;
                    }
                }

                bool isDisabled = PatchDisabler.IsDisabled(r.Method);
                if (ButtonText(buttonRect3, isDisabled ? "On" : "Off", tooltip + (isDisabled ? "\nPress for ENABLE this method" : "\nPress for DISABLE this method"), out bool button3IsMouseOver))
                {
                    if (isDisabled)
                    {
                        PatchDisabler.EnableMethod(r.Method);
                    }
                    else
                    {
                        PatchDisabler.DisableMethod(r.Method);
                    }
                }

                if (ButtonText(buttonRect4, "Undo", tooltip + ("\nPress for REMOVE PROFILER for this method"), out bool button4IsMouseOver))
                {
                    Patcher.UnpatchMethod(r.Method);
                    cached = null;
                    break; // and redraw
                }

                if (ButtonText(buttonRect5, r.MethodName, tooltip + "\nPress for hide this line", out bool button5IsMouseOver))
                {
                    hided.Add(r.MethodName);
                    cached = null;
                    break; // and redraw
                }

                if (button1IsMouseOver || button2IsMouseOver || button3IsMouseOver || button4IsMouseOver || button5IsMouseOver)
                {
                    stopUpdate = true;
                }

                lister.Label($"  TimeSpent:{r.TimeSpent}ms AvgTick:{r.AvgTime:0.00000}ms Ticks:{r.TicksNum}");
            }
            Text.Font = backFont;

            if (hided.Count > 0 && lister.ButtonText($"Reset Hided", Text.LineHeight))
            {
                hided.Clear();
                cached = null;
            }
        }
コード例 #12
0
        private void DrawOther(Listing_Extended lister, Settings settings)
        {
            if (lister.ButtonText($"Results", Text.LineHeight))
            {
                Find.WindowStack.Add(new FloatMenu(new List <FloatMenuOption>
                {
                    new FloatMenuOption("Dump to SLK", () => {
                        List <StopwatchRecord> result = PatchHandler.GetProfileRecordsSorted();
                        FS.WriteAllText($"Profiler_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.slk", result.DumpToSlk());
                    }),
                    new FloatMenuOption("Dump to CSV", () => {
                        List <StopwatchRecord> result = PatchHandler.GetProfileRecordsSorted();
                        FS.WriteAllText($"Profiler_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.csv", result.DumpToCsv());
                    }),
                    new FloatMenuOption("Reset results", () => {
                        PatchHandler.Reset();
                    }),
                }));
            }
            if (lister.ButtonText($"Tools / Other", Text.LineHeight))
            {
                IEnumerable <FloatMenuOption> getOptions()
                {
                    yield return(new FloatMenuOption($"Enable disabled methods: {PatchDisabler.DisabledCount}", () =>
                    {
                        PatchDisabler.EnableAllDisabled();
                    }));

                    yield return(new FloatMenuOption("Dump all harmony patches", () =>
                    {
                        FS.WriteAllText("HarmonyPatches.txt", HarmonyMain.AllHarmonyPatchesDump());
                        FS.WriteAllText("HarmonyPatches-Conflicts.txt", HarmonyMain.CanConflictHarmonyPatchesDump());
                    }));
                    // if (DubsProfilerReset.CanUnpatch())
                    // {
                    //     yield return new FloatMenuOption("Reset DubsPerfomanceAnalyzer patches", DubsProfilerReset.ResetProfiler);
                    // }
                }

                Find.WindowStack.Add(new FloatMenu(new List <FloatMenuOption>(getOptions())));
            }

            // Method resolver. Handle string >= 3 chars. Results show after 2 sec. when str not changed. Has filter AND, example: 'pawn tick' => Verse.Pawn:Tick
            {
                var  prevStr      = _methodResolver;
                Rect labelRect    = lister.GetRect(Text.LineHeight),
                     textEntyRect = labelRect;

                float width = labelRect.width;
                labelRect.width    = width / 3;
                textEntyRect.width = 2 * width / 3;
                textEntyRect.x     = labelRect.xMax;
                Widgets.Label(labelRect, $"Method resolver");
                _methodResolver = Widgets.TextArea(textEntyRect, _methodResolver);
                if (!String.IsNullOrWhiteSpace(_methodResolver) && _methodResolver.Length >= 4)
                {
                    if (!prevStr.Equals(_methodResolver))
                    {
                        _methodResolverInputTimer = Stopwatch.StartNew();
                    }
                }
                else
                {
                    _methodResolverInputTimer = null;
                }

                if (_methodResolverInputTimer != null &&
                    _methodResolverInputTimer.ElapsedMilliseconds > 1500)
                {
                    var strLower   = _methodResolver.ToLower();
                    var arrFilters = strLower.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                    var allMethods = Utils.GetAllMethods();

                    IEnumerable <string> filterMethods()
                    {
                        if (_methodResolverCache == null)
                        {
                            _methodResolverCache = allMethods
                                                   .OrderBy(x => x)
                                                   .Select(x => (x, x.ToLower()))
                                                   .ToList();
                        }
                        foreach (var m in (from tuple in _methodResolverCache
                                           where arrFilters.All(x => tuple.nameLower.Contains(x))
                                           select tuple))
                        {
                            yield return(m.name);
                        }
                    }

                    IEnumerable <FloatMenuOption> makeVariants(int maxResult)
                    {
                        foreach (var m in filterMethods().OrderBy(x => x))
                        {
                            if (maxResult-- < 0)
                            {
                                break;
                            }
                            yield return(new FloatMenuOption(m, () => _methodResolver = m));
                        }
                    }

                    Find.WindowStack.Add(new FloatMenu(new List <FloatMenuOption>(makeVariants(20))));
                    _methodResolverInputTimer = null;
                }
            }
            lister.CheckboxLabeled("CRASH DEBUG", ref settings.debug);
            lister.Gap(20f);
        }
コード例 #13
0
        private void DrawSettings(Listing_Extended lister, Settings settings)
        {
            lister.LabelColored("Settings", TitleLabelColor);
            lister.CheckboxLabeled("Check main thread", ref settings.checkMainThread);
            lister.CheckboxLabeled("Transpiler Mode(SLOW PATCHING/BETTER TPS)", ref settings.profilerTranspileMode);
            if (settings.profilerTranspileMode)
            {
                lister.CheckboxLabeled("  Get original from dictionary", ref settings.getOriginalFromDict);
            }
            // memory options
            {
                bool prevColMemUs = settings.collectMemAlloc;
                lister.CheckboxLabeled("Collect memory allocations", ref settings.collectMemAlloc);
                if (prevColMemUs != settings.collectMemAlloc)
                {
                    if (!settings.collectMemAlloc)
                    {
                        settings.sortByMemAlloc = false;
                    }
                    PatchHandler.Reset();
                }
                if (settings.collectMemAlloc)
                {
                    lister.CheckboxLabeled("  Sort by memory allocations", ref settings.sortByMemAlloc);
                }
            }
            // perfomance mode
            Rect checkboxRect = lister.GetRect(Text.LineHeight),
                 buttonRect   = checkboxRect;

            if (settings.perfomanceMode)
            {
                buttonRect.width = checkboxRect.width /= 2;
                buttonRect.x     = checkboxRect.xMax;
                if (Widgets.ButtonText(buttonRect, "Force optimize"))
                {
                    Patcher.UnpatchByRule(settings.ruleTiming, settings.ruleTicks);
                }
            }

            Widgets.CheckboxLabeled(checkboxRect, "Perfomance mode", ref settings.perfomanceMode);
            {
                if (settings.perfomanceMode)
                {
                    Rect rect      = lister.GetRect(Text.LineHeight),
                         timeRect  = rect,
                         ticksRect = rect;

                    timeRect.width = rect.width / 2 + 35;
                    Widgets.TextFieldNumericLabeled(timeRect, "clean AvgTime < ", ref settings.ruleTiming, ref settings.ruleTimingBuf);

                    ticksRect.x      = timeRect.xMax;
                    ticksRect.width -= timeRect.width;
                    Widgets.TextFieldNumericLabeled(ticksRect, "and Ticks > ", ref settings.ruleTicks, ref settings.ruleTicksBuf);
                }
            }
            if (lister.ButtonText($"Stop profiling", Text.LineHeight))
            {
                Profiler.Logger.LogOperation("ResetProfiling", Patcher.UnpatchAll);
                PatchHandler.ClearGetMethodByKey();
            }
        }
コード例 #14
0
        private void DrawCustomProfiler(Listing_Extended lister, Settings settings)
        {
            lister.LabelColored("Profile Custom(Methods,Classes,Namespaces)", TitleLabelColor);
            Rect buttonRect1 = lister.GetRect(Text.LineHeight),
                 buttonRect2 = buttonRect1;

            buttonRect2.width = buttonRect1.width /= 2;
            buttonRect2.x     = buttonRect1.xMax;

            if (Widgets.ButtonText(buttonRect1, "Profile all dlls"))
            {
                PatchHandler.Initialize();
                var methods     = new HashSet <string>();
                var modDllNames = Utils.GetAllModsDll();
                //File.WriteAllLines("dsdsd", modDllNames.ToArray());
                foreach (var modDllName in modDllNames)
                {
                    //Log.Warning($"[dll] {modDllName}");
                    foreach (var @class in Utils.GetClassesFromDll(modDllName))
                    {
                        methods.AddDefMethodsAdvanced(@class, settings.allowCoreAsm, !settings.allowInheritedMethods);
                    }
                }
                Profiler.Logger.LogOperation("DllProfiling", () => Patcher.ProfileMethods(methods.ToArray()));
            }

            //if (!settings.profileCustom.IsNullOrEmptyOrEqual(Settings.CustomExampleStr))
            {
                lister.CheckboxLabeled("Allow Core assembly", ref settings.allowCoreAsm);
                lister.CheckboxLabeled("Allow class inherited methods", ref settings.allowInheritedMethods);
                if (Widgets.ButtonText(buttonRect2, $"Profile custom methods"))
                {
                    PatchHandler.Initialize();
                    var methods = new HashSet <string>();
                    var list    = settings.profileCustom.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var s in list)
                    {
                        // it's method
                        if (s.Contains(":"))
                        {
                            methods.Add(s);
                        }
                        else if (s.EndsWith(".dll"))
                        {
                            string dllName = s.Replace(".dll", "");
                            foreach (var @class in Utils.GetClassesFromDll(dllName))
                            {
                                methods.AddDefMethodsAdvanced(@class, settings.allowCoreAsm, !settings.allowInheritedMethods);
                            }
                        }
                        else
                        {
                            Type type = AccessTools.TypeByName(s);
                            // it's class
                            if (type?.IsClass ?? false)
                            {
                                methods.AddDefMethodsAdvanced(type, settings.allowCoreAsm, !settings.allowInheritedMethods);
                            }
                            else // parse namespace
                            {
                                var classes = Utils.GetClassesFromNamespace(s);
                                if (!classes.Any())
                                {
                                    Log.Error($"[HarmonyProfiler] Found 0 results for namespace:'{s}'");
                                }
                                foreach (var @class in classes)
                                {
                                    methods.AddDefMethodsAdvanced(@class, settings.allowCoreAsm, !settings.allowInheritedMethods);
                                }
                            }
                        }
                    }

                    Profiler.Logger.LogOperation("CustomProfiling", () => Patcher.ProfileMethods(methods.ToArray()));
                }
            }

            settings.profileCustom = lister.TextAreaFocusControl("CustomProfilerField", settings.profileCustom, 5, ref customScrollPos);
            lister.Gap(20f);
        }