private static bool Matched(ProfileLog log, string s) { if (s == string.Empty) { Panel_TopRow.MatchType = string.Empty; return(true); } if (log.meth != null && log.meth.Name.ContainsCaseless(s)) { Panel_TopRow.MatchType = "Assembly"; return(true); } if (log.type != null && log.type.Assembly.FullName.ContainsCaseless(s)) { Panel_TopRow.MatchType = "Assembly"; return(true); } if (log.label.ContainsCaseless(s)) { Panel_TopRow.MatchType = "Label"; return(true); } return(false); }
public string Value(ProfileLog log) { switch (sortBy) { case SortBy.Average: return($" {log.average:0.000}ms "); case SortBy.Max: return($" {log.max:0.000}ms "); case SortBy.Calls: return($" {log.calls.ToString("N0", CultureInfo.InvariantCulture)} "); case SortBy.AvPc: return($" {log.total/log.calls:0.000}ms "); case SortBy.Percent: return($" {log.percent * 100:0.0}% "); case SortBy.Name: return(" " + log.label); case SortBy.Total: return($" {log.total:0.000}ms "); case SortBy.CallsPu: var num = log.calls / log.entries; return(num < 1 ? $" {num:F3}" : $" {(int)Math.Round(num)}"); } return(""); }
public static void Checkbox(ref Rect rect, ProfileLog log, Profiler profile, ref bool active) { var checkboxRect = new Rect(rect.x, rect.y, 25f, rect.height); rect.x += 25f; if (DubGUI.Checkbox(checkboxRect, "", ref active)) { GUIController.CurrentEntry.checkBox.Invoke(null, new object[] { log }); Modbase.Settings.Write(); } }
public static void DrawHover(ProfileLog log, Rect visible) { if (log.meth != null) { if (log.label != tipLabelCache) // If we have a new label, re-create the string, else use our cached version. { tipLabelCache = log.label; StringBuilder builder = new StringBuilder(); Patches patches = Harmony.GetPatchInfo(log.meth); if (patches != null) { foreach (Patch patch in patches.Prefixes) { GetString("Prefix", patch); } foreach (Patch patch in patches.Postfixes) { GetString("Postfix", patch); } foreach (Patch patch in patches.Transpilers) { GetString("Transpiler", patch); } foreach (Patch patch in patches.Finalizers) { GetString("Finalizer", patch); } void GetString(string type, Patch patch) { if (Utility.IsNotAnalyzerPatch(patch.owner)) { string ass = patch.PatchMethod.DeclaringType.Assembly.FullName; string modName = ModInfoCache.AssemblyToModname[ass]; builder.AppendLine($"{type} from {modName} with the index {patch.index} and the priority {patch.priority}\n"); } } tipCache = builder.ToString(); } } TooltipHandler.TipRegion(visible, tipCache); } }
private static IEnumerable <FloatMenuOption> RightClickDropDown(ProfileLog log, Profiler profiler) { var meth = log.meth as MethodInfo; if (Input.GetKey(KeyCode.LeftShift)) { if (GUIController.CurrentEntry.name.Contains("Harmony")) // we can return an 'unpatch' for methods in a harmony tab { yield return(new FloatMenuOption("Unpatch Method (Destructive)", () => Utility.UnpatchMethod(meth))); } yield return(new FloatMenuOption("Unpatch methods that patch (Destructive)", () => Utility.UnpatchMethodsOnMethod(meth))); } var message = profiler.pinned ? "Unpin profile from entry" : "Pin profile to the top of the entry"; yield return(new FloatMenuOption(message, () => profiler.pinned = !profiler.pinned)); if (GUIController.CurrentEntry.type != typeof(H_HarmonyTranspilersInternalMethods)) { yield return(new FloatMenuOption("Profile the internal methods of", () => Utility.PatchInternalMethod(meth, GUIController.CurrentCategory))); } // This part is WIP - it would require the ability to change the tab a method is active in on the fly // which is possible (with a transpiler to the current transpiler) but it would likely end up being // quite ugly, and I'd rather give a little more thought to the problem //yield return new FloatMenuOption("Profile in Custom Tab", () => //{ // if (GUIController.CurrentCategory == Category.Tick) // { // MethodTransplanting.UpdateMethod(typeof(CustomProfilersTick), meth); // GUIController.SwapToEntry("Custom Tick"); // } // else // { // MethodTransplanting.UpdateMethod(typeof(CustomProfilersUpdate), meth); // GUIController.SwapToEntry("Custom Update"); // } //}); }
public static void ClickWork(ProfileLog log, Profiler profile) { if (Event.current.button == 0) // left click { if (Input.GetKey(KeyCode.LeftControl)) { GUIController.CurrentEntry.onClick?.Invoke(null, new object[] { profile, log }); Modbase.Settings.Write(); } else { if (GUIController.CurrentProfiler == profile) { GUIController.CurrentProfiler = null; } else // This is now the 'active' profile { GUIController.CurrentProfiler = profile; } } } else if (Event.current.button == 1) // right click { if (log.meth == null) { return; } var options = RightClickDropDown(log, profile).ToList(); if (options.Count != 0) { Find.WindowStack.Add(new FloatMenu(options)); } } }
public static void OnSelect(ProfileLog log, Profiler profile, out bool active) { active = (bool)GUIController.CurrentEntry.onSelect.Invoke(null, new object[] { profile, log }); }
private static void DrawLog(ProfileLog log, ref float currentListHeight) { if (log.pinned is false && Matched(log, Panel_TopRow.TimesFilter) is false) { return; } columns[(int)SortBy.Average].total += log.average; var visible = listing.GetRect(BOX_HEIGHT); if (!visible.Overlaps(viewFrustum)) // if we don't overlap, continue, but continue to adjust for further logs. { listing.GapLine(0f); currentListHeight += (BOX_HEIGHT + 4); return; } var profile = ProfileController.Profiles[log.key]; // Is this entry currently 'active'? if (GUIController.CurrentEntry.onSelect != null) { OnSelect(log, profile, out var active); // Show a button to toggle whether an entry is 'active' if (GUIController.CurrentEntry.checkBox != null) { Checkbox(ref visible, log, profile, ref active); } } Widgets.DrawHighlightIfMouseover(visible); if (GUIController.CurrentProfiler?.key == profile.key) { Widgets.DrawHighlightSelected(visible); } // onclick work, left click view stats, right click internal patch, ctrl + left click unpatch if (Widgets.ButtonInvisible(visible)) { ClickWork(log, profile); } // Colour a fillable bar below the log depending on the % fill of a log var colour = Textures.grey; if (log.percent <= .25f) { colour = Textures.grey; // <= 25% } else if (log.percent <= .75f) { colour = Textures.blue; // 25% < x <=75% } else if (log.percent <= .999) { colour = Textures.red; // 75% < x <= 99.99% (we want 100% to be grey) } Widgets.FillableBar(visible.BottomPartPixels(8f), log.percent, colour, Textures.clear, false); Text.Anchor = TextAnchor.MiddleCenter; foreach (var column in columns.Where(c => c.Active(GUIController.CurrentEntry.type)).OrderBy(c => c.order)) { DrawColumnContents(ref visible, column, column.Value(log), profile); } GUI.color = Color.white; listing.GapLine(0f); currentListHeight += (BOX_HEIGHT + 4); }
private static void DrawLog(ProfileLog log, ref float currentListHeight) { if (Panel_TopRow.TimesFilter != "") { if (!log.label.ToLower().Contains(Panel_TopRow.TimesFilter.ToLower())) { return; } } Rect visible = listing.GetRect(BOX_HEIGHT); if (!visible.Overlaps(viewFrustum)) // if we don't overlap, continue, but continue to adjust for further logs. { listing.GapLine(0f); currentListHeight += (BOX_HEIGHT + 4); return; } Profiler profile = ProfileController.Profiles[log.key]; // Is this entry currently 'active'? if (GUIController.CurrentEntry.onSelect != null) { OnSelect(log, profile, out var active); // Show a button to toggle whether an entry is 'active' if (GUIController.CurrentEntry.checkBox != null) { Checkbox(ref visible, log, profile, ref active); } } Widgets.DrawHighlightIfMouseover(visible); if (GUIController.CurrentProfiler?.key == profile.key) { Widgets.DrawHighlightSelected(visible); } // onhover tooltip if (Mouse.IsOver(visible)) { DrawHover(log, visible); } // onclick work, left click view stats, right click internal patch, ctrl + left click unpatch if (Widgets.ButtonInvisible(visible)) { ClickWork(log, profile); } // Colour a fillable bar below the log depending on the % fill of a log var colour = ResourceCache.GUI.grey; if (log.percent <= .25f) { colour = ResourceCache.GUI.grey; // <= 25% } else if (log.percent <= .75f) { colour = ResourceCache.GUI.blue; // 25% < x <=75% } else if (log.percent <= .999) { colour = ResourceCache.GUI.red; // 75% < x <= 99.99% (we want 100% to be grey) } Widgets.FillableBar(visible.BottomPartPixels(8f), log.percent, colour, ResourceCache.GUI.clear, false); Text.Anchor = TextAnchor.MiddleCenter; DrawColumnContents(ref visible, $" {log.max:0.000}ms ", SortBy.Max); DrawColumnContents(ref visible, $" {log.average:0.000}ms ", SortBy.Average); DrawColumnContents(ref visible, $" {log.percent * 100:0.0}% ", SortBy.Percent); DrawColumnContents(ref visible, $" {log.total:0.000}ms ", SortBy.Total); if (GUIController.CurrentEntry.type != typeof(H_HarmonyTranspilers)) { DrawColumnContents(ref visible, $" {log.calls.ToString("N0", CultureInfo.InvariantCulture)} ", SortBy.Calls); } Text.Anchor = TextAnchor.MiddleLeft; visible.width = 10000; DrawColumnContents(ref visible, " " + log.label, SortBy.Name); GUI.color = Color.white; listing.GapLine(0f); currentListHeight += (BOX_HEIGHT + 4); }