Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimPerformanceAnalyzer v1.0.1
BepInEx/plugins/ValheimPerformanceAnalyzer/ValheimPerformanceAnalyzer.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ValheimPerformanceAnalyzer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("ValheimPerformanceAnalyzer")] [assembly: AssemblyTitle("ValheimPerformanceAnalyzer")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ValheimPerformanceAnalyzer { internal static class CaptureStatusBuff { private const float RefreshInterval = 0.5f; private static StatusEffect _statusEffect; private static Texture2D _iconTexture; private static Sprite _icon; private static Character _appliedTo; private static double _nextRefresh; private static bool _wasCapturing; internal static void Update(bool capturing) { double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble; if (capturing == _wasCapturing && realtimeSinceStartupAsDouble < _nextRefresh) { return; } _wasCapturing = capturing; _nextRefresh = realtimeSinceStartupAsDouble + 0.5; Player localPlayer = Player.m_localPlayer; if (!capturing || (Object)(object)localPlayer == (Object)null) { if (!capturing) { RemoveFrom((Character)(((object)localPlayer) ?? ((object)_appliedTo))); } return; } double num = Math.Max(0.0, (double)ProfilerCollector.DurationLimitSeconds - ProfilerCollector.ElapsedSeconds); if (num <= 0.0) { return; } SEMan sEMan = ((Character)localPlayer).GetSEMan(); if (sEMan != null) { StatusEffect val = EnsureStatusEffect(num); int num2 = val.NameHash(); if ((Object)(object)_appliedTo != (Object)(object)localPlayer || !sEMan.HaveStatusEffect(num2)) { RemoveFrom(_appliedTo); val.m_ttl = (float)num; sEMan.AddStatusEffect(val, true, 0, 0f, (short)0); _appliedTo = (Character)(object)localPlayer; } } } internal static void Clear() { RemoveFrom((Character)(((object)_appliedTo) ?? ((object)Player.m_localPlayer))); if ((Object)(object)_icon != (Object)null) { Object.Destroy((Object)(object)_icon); } if ((Object)(object)_iconTexture != (Object)null) { Object.Destroy((Object)(object)_iconTexture); } _icon = null; _iconTexture = null; _statusEffect = null; _appliedTo = null; _wasCapturing = false; _nextRefresh = 0.0; } private static StatusEffect EnsureStatusEffect(double remaining) { if ((Object)(object)_statusEffect != (Object)null) { return _statusEffect; } _statusEffect = ScriptableObject.CreateInstance<StatusEffect>(); ((Object)_statusEffect).name = "ValheimPerformanceAnalyzer_CaptureStatus"; _statusEffect.m_name = ProfilerTranslations.Text("capture_buff"); _statusEffect.m_tooltip = ProfilerTranslations.Text("capture_buff_tooltip"); _statusEffect.m_ttl = (float)remaining; _statusEffect.m_icon = EnsureIcon(); _statusEffect.m_hidden = false; _statusEffect.m_flashIcon = false; _statusEffect.m_cooldownIcon = false; _statusEffect.m_startMessage = string.Empty; _statusEffect.m_stopMessage = string.Empty; _statusEffect.m_repeatMessage = string.Empty; return _statusEffect; } private static void RemoveFrom(Character character) { if ((Object)(object)character == (Object)null || (Object)(object)_statusEffect == (Object)null) { return; } try { SEMan sEMan = character.GetSEMan(); if (sEMan != null) { sEMan.RemoveStatusEffect(_statusEffect.NameHash(), true); } } catch { } if ((Object)(object)_appliedTo == (Object)(object)character) { _appliedTo = null; } } private static Sprite EnsureIcon() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_icon != (Object)null) { return _icon; } _iconTexture = new Texture2D(32, 32, (TextureFormat)4, false) { name = "ValheimPerformanceAnalyzer_CaptureIcon", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color32[] array = (Color32[])(object)new Color32[1024]; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = (float)j - 15.5f; float num2 = (float)i - 15.5f; float num3 = Mathf.Sqrt(num * num + num2 * num2); int num4 = i * 32 + j; if (num3 <= 14f && num3 >= 10.5f) { array[num4] = new Color32((byte)70, (byte)205, (byte)224, byte.MaxValue); } else if (num3 < 10.5f) { array[num4] = new Color32((byte)20, (byte)47, (byte)62, byte.MaxValue); } bool flag = j >= 15 && j <= 16 && i >= 16 && i <= 23; bool flag2 = i >= 15 && i <= 16 && j >= 15 && j <= 22; if (num3 <= 10.5f && (flag || flag2)) { array[num4] = new Color32((byte)245, (byte)249, (byte)252, byte.MaxValue); } } } _iconTexture.SetPixels32(array); _iconTexture.Apply(false, false); _icon = Sprite.Create(_iconTexture, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 100f); ((Object)_icon).name = "ValheimPerformanceAnalyzer_CaptureIcon"; ((Object)_icon).hideFlags = (HideFlags)61; return _icon; } } internal static class OverlayInputGuard { private static readonly BindingFlags MethodFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static Harmony _harmony; private static bool _eventSystemUpdatePatched; internal static void Install(Harmony harmony) { if (harmony != null) { _harmony = harmony; _eventSystemUpdatePatched = false; Patch(harmony, "GetButtonDown", new Type[1] { typeof(string) }, "BlockBoolean"); Patch(harmony, "GetButtonUp", new Type[1] { typeof(string) }, "BlockBoolean"); Patch(harmony, "GetButton", new Type[1] { typeof(string) }, "BlockBoolean"); Patch(harmony, "GetMouseButtonDown", new Type[1] { typeof(int) }, "BlockBoolean"); Patch(harmony, "GetMouseButtonUp", new Type[1] { typeof(int) }, "BlockBoolean"); Patch(harmony, "GetMouseButton", new Type[1] { typeof(int) }, "BlockBoolean"); Patch(harmony, "GetMouseDelta", Type.EmptyTypes, "BlockVector2"); Patch(harmony, "Internal_GetMouseDelta", Type.EmptyTypes, "BlockVector2"); Patch(harmony, "GetMouseScrollWheel", Type.EmptyTypes, "BlockFloat"); PatchPlayerControls(harmony); PatchEventSystemUpdate(); } } private static void PatchPlayerControls(Harmony harmony) { try { Type typeFromHandle = typeof(Player); PatchPlayerMethod(harmony, typeFromHandle, "TakeInput", Type.EmptyTypes, "BlockPlayerInput"); PatchPlayerMethod(harmony, typeFromHandle, "PlayerAttackInput", new Type[1] { typeof(float) }, "BlockPlayerAction"); PatchPlayerMethod(harmony, typeFromHandle, "Interact", new Type[3] { typeof(GameObject), typeof(bool), typeof(bool) }, "BlockPlayerAction"); PatchPlayerMethod(harmony, typeFromHandle, "UseHotbarItem", new Type[1] { typeof(int) }, "BlockPlayerAction"); PatchPlayerMethod(harmony, typeFromHandle, "Dodge", new Type[1] { typeof(Vector3) }, "BlockPlayerAction"); PatchPlayerMethod(harmony, typeFromHandle, "UpdateBuildGuiInput", Type.EmptyTypes, "BlockPlayerAction"); PatchPlayerMethod(harmony, typeFromHandle, "UpdateBuildGuiInputAlternative1", Type.EmptyTypes, "BlockPlayerAction"); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Input guard não conseguiu bloquear as ações do personagem: " + ex.GetType().Name)); } } } private static void PatchPlayerMethod(Harmony harmony, Type playerType, string methodName, Type[] parameters, string prefixName) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown try { MethodInfo method = playerType.GetMethod(methodName, MethodFlags, null, parameters, null); MethodInfo method2 = typeof(OverlayInputGuard).GetMethod(prefixName, BindingFlags.Static | BindingFlags.NonPublic); if (method != null && method2 != null) { harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("Input guard: método Player não encontrado: " + methodName)); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("Input guard não conseguiu aplicar " + methodName + ": " + ex.GetType().Name)); } } } private static void Patch(Harmony harmony, string methodName, Type[] parameters, string prefixName) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown try { MethodInfo method = typeof(ZInput).GetMethod(methodName, MethodFlags, null, parameters, null); MethodInfo method2 = typeof(OverlayInputGuard).GetMethod(prefixName, BindingFlags.Static | BindingFlags.NonPublic); if (method != null && method2 != null) { harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return; } ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Input guard: método ZInput não encontrado: " + methodName)); } } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("Input guard não conseguiu aplicar " + methodName + ": " + ex.GetType().Name)); } } } [HarmonyPriority(800)] private static bool BlockBoolean(ref bool __result) { if ((Object)(object)Plugin.Runner == (Object)null || !Plugin.Runner.OverlayVisible) { return true; } __result = false; return false; } [HarmonyPriority(800)] private static bool BlockVector2(ref Vector2 __result) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Plugin.Runner == (Object)null || !Plugin.Runner.OverlayVisible) { return true; } __result = Vector2.zero; return false; } [HarmonyPriority(800)] private static bool BlockFloat(ref float __result) { if ((Object)(object)Plugin.Runner == (Object)null || !Plugin.Runner.OverlayVisible) { return true; } __result = 0f; return false; } internal static void Update() { PatchEventSystemUpdate(); } private static void PatchEventSystemUpdate() { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown if (_eventSystemUpdatePatched || _harmony == null) { return; } try { Type type = ResolveEventSystemType(); if (!(type == null)) { MethodInfo method = type.GetMethod("Update", MethodFlags, null, Type.EmptyTypes, null); MethodInfo method2 = typeof(OverlayInputGuard).GetMethod("BlockEventSystemUpdate", BindingFlags.Static | BindingFlags.NonPublic); if (!(method == null) && !(method2 == null)) { _harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _eventSystemUpdatePatched = true; } } } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("Input guard não conseguiu proteger o EventSystem: " + ex.GetType().Name)); } } } [HarmonyPriority(800)] private static bool BlockEventSystemUpdate() { if (!((Object)(object)Plugin.Runner == (Object)null)) { return !Plugin.Runner.OverlayVisible; } return true; } [HarmonyPriority(800)] private static bool BlockPlayerInput(ref bool __result) { if ((Object)(object)Plugin.Runner == (Object)null || !Plugin.Runner.OverlayVisible) { return true; } __result = false; return false; } [HarmonyPriority(800)] private static bool BlockPlayerAction() { if (!((Object)(object)Plugin.Runner == (Object)null)) { return !Plugin.Runner.OverlayVisible; } return true; } private static Type ResolveEventSystemType() { Type type = Type.GetType("UnityEngine.EventSystems.EventSystem, UnityEngine.UI", throwOnError: false); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { type = assembly.GetType("UnityEngine.EventSystems.EventSystem", throwOnError: false); if (type != null) { return type; } } catch { } } return null; } } internal sealed class PerformanceOverlay : MonoBehaviour { private const int WindowId = 827164; private const int ResizeControlId = 827165; private const float ResizeEdgeSize = 9f; private const int ResizeLeft = 1; private const int ResizeRight = 2; private const int ResizeTop = 4; private const int ResizeBottom = 8; private const float MinimumWindowWidth = 940f; private const float MinimumWindowHeight = 420f; private Rect _window = new Rect(24f, 24f, 1120f, 735f); private Vector2 _scroll; private bool _resizing; private int _resizeEdges; private Vector2 _resizeStartMouse; private Rect _resizeStartWindow; private int _tab; private int _visibleObjectsPage; private int _visibleObjectIdsPage; private string _expandedVisibleObjectKey; private bool _visible = true; private readonly HashSet<string> _expandedAssemblies = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, int> ExpandedMethodPages = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private static int _modsPage; private const int VisibleObjectsPageSize = 50; private const int VisibleObjectIdsPageSize = 30; private const int ExpandedMethodsPageSize = 50; private const int ExpandedMethodsRenderBudget = 50; private static Texture2D _windowTexture; private static Texture2D _surfaceTexture; private static Texture2D _raisedTexture; private static Texture2D _headerTexture; private static Texture2D _stripeTexture; private static Texture2D _accentTexture; private static Texture2D _goodTexture; private static Texture2D _warnTexture; private static Texture2D _badTexture; private static Texture2D _buttonHoverTexture; private static Texture2D _buttonPressedTexture; private static GUIStyle _windowStyle; private static GUIStyle _surfaceStyle; private static GUIStyle _accentCardStyle; private static GUIStyle _goodCardStyle; private static GUIStyle _warnCardStyle; private static GUIStyle _badCardStyle; private static GUIStyle _headerStyle; private static GUIStyle _rowStyle; private static GUIStyle _alternateRowStyle; private static GUIStyle _labelStyle; private static GUIStyle _mutedStyle; private static GUIStyle _titleStyle; private static GUIStyle _sectionStyle; private static GUIStyle _buttonStyle; private static GUIStyle _objectCaptureOptionalStyle; private static GUIStyle _objectCaptureEnabledStyle; private static GUIStyle _startButtonStyle; private static GUIStyle _tabStyle; private static GUIStyle _activeTabStyle; private static GUIStyle _goodStyle; private static GUIStyle _warnStyle; private static GUIStyle _badStyle; private static GUIStyle _metricStyle; private static GUIStyle _closeButtonStyle; private static GUIStyle _captureTimerPanelStyle; private static GUIStyle _captureTimerLabelStyle; private static GUIStyle _captureTimerValueStyle; private static GUIStyle _tooltipStyle; internal void SetVisible(bool visible) { _visible = visible; } private void OnGUI() { //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) if (_visible) { EnsureStyles(); float num = Mathf.Min(940f, Mathf.Max(580f, (float)Screen.width - 16f)); float num2 = Mathf.Min(420f, Mathf.Max(340f, (float)Screen.height - 16f)); ((Rect)(ref _window)).width = Mathf.Clamp(((Rect)(ref _window)).width, num, Mathf.Max(num, (float)Screen.width - 16f)); ((Rect)(ref _window)).height = Mathf.Clamp(((Rect)(ref _window)).height, num2, Mathf.Max(num2, (float)Screen.height - 16f)); ((Rect)(ref _window)).x = Mathf.Clamp(((Rect)(ref _window)).x, 4f, Mathf.Max(4f, (float)Screen.width - ((Rect)(ref _window)).width - 4f)); ((Rect)(ref _window)).y = Mathf.Clamp(((Rect)(ref _window)).y, 4f, Mathf.Max(4f, (float)Screen.height - ((Rect)(ref _window)).height - 4f)); HandleResizeInput(num, num2); GUI.color = Color.white; _window = GUI.Window(827164, _window, new WindowFunction(DrawWindow), GUIContent.none, _windowStyle); } } private void HandleResizeInput(float minimumWidth, float minimumHeight) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Invalid comparison between Unknown and I4 //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Invalid comparison between Unknown and I4 //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current == null || (Object)(object)Plugin.Runner == (Object)null || !Plugin.Runner.MouseReleased) { return; } Vector2 mousePosition = current.mousePosition; if (!_resizing && (int)current.type == 0 && current.button == 0) { bool num = mousePosition.x >= ((Rect)(ref _window)).x - 9f && mousePosition.x <= ((Rect)(ref _window)).xMax + 9f; bool flag = mousePosition.y >= ((Rect)(ref _window)).y - 9f && mousePosition.y <= ((Rect)(ref _window)).yMax + 9f; if (num && flag) { if (Mathf.Abs(mousePosition.x - ((Rect)(ref _window)).x) <= 9f) { _resizeEdges |= 1; } if (Mathf.Abs(mousePosition.x - ((Rect)(ref _window)).xMax) <= 9f) { _resizeEdges |= 2; } if (Mathf.Abs(mousePosition.y - ((Rect)(ref _window)).y) <= 9f) { _resizeEdges |= 4; } if (Mathf.Abs(mousePosition.y - ((Rect)(ref _window)).yMax) <= 9f) { _resizeEdges |= 8; } if (_resizeEdges != 0) { _resizing = true; _resizeStartMouse = mousePosition; _resizeStartWindow = _window; GUIUtility.hotControl = 827165; current.Use(); } } } else { if (!_resizing || GUIUtility.hotControl != 827165) { return; } if ((int)current.type == 3) { float num2 = mousePosition.x - _resizeStartMouse.x; float num3 = mousePosition.y - _resizeStartMouse.y; float num4 = ((Rect)(ref _resizeStartWindow)).x; float num5 = ((Rect)(ref _resizeStartWindow)).y; float num6 = ((Rect)(ref _resizeStartWindow)).width; float num7 = ((Rect)(ref _resizeStartWindow)).height; if ((_resizeEdges & 1) != 0) { num4 += num2; num6 -= num2; } if ((_resizeEdges & 2) != 0) { num6 += num2; } if ((_resizeEdges & 4) != 0) { num5 += num3; num7 -= num3; } if ((_resizeEdges & 8) != 0) { num7 += num3; } if (num6 < minimumWidth) { if ((_resizeEdges & 1) != 0) { num4 = ((Rect)(ref _resizeStartWindow)).xMax - minimumWidth; } num6 = minimumWidth; } if (num7 < minimumHeight) { if ((_resizeEdges & 4) != 0) { num5 = ((Rect)(ref _resizeStartWindow)).yMax - minimumHeight; } num7 = minimumHeight; } num6 = Mathf.Min(num6, Mathf.Max(minimumWidth, (float)Screen.width - 8f)); num7 = Mathf.Min(num7, Mathf.Max(minimumHeight, (float)Screen.height - 8f)); num4 = Mathf.Clamp(num4, 4f, Mathf.Max(4f, (float)Screen.width - num6 - 4f)); num5 = Mathf.Clamp(num5, 4f, Mathf.Max(4f, (float)Screen.height - num7 - 4f)); _window = new Rect(num4, num5, num6, num7); current.Use(); } else if ((int)current.type == 1 && current.button == 0) { _resizing = false; _resizeEdges = 0; GUIUtility.hotControl = 0; current.Use(); } } } private void DrawWindow(int id) { //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(_headerStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }); GUILayout.Label("VALHEIM PERFORMANCE ANALYZER", _titleStyle, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.Label("F9 " + ProfilerTranslations.Text("panel_short"), _mutedStyle, Array.Empty<GUILayoutOption>()); if (GUILayout.Button("×", _closeButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(32f), GUILayout.Height(27f) })) { Plugin.Runner?.CloseOverlay(); } GUILayout.EndHorizontal(); GUILayout.Space(6f); DrawToolbar(); DrawStatus(); GUILayout.Space(7f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); float width = Mathf.Clamp((((Rect)(ref _window)).width - 290f) / 5f, 116f, 138f); DrawTab(0, "tab_summary", width); DrawTab(1, "tab_callbacks", width); DrawTab(2, "tab_mods", width); DrawTab(3, "tab_components", width); DrawTab(4, "tab_visible_objects", width); if (GUILayout.Button((Plugin.HideValheimCallbacks.Value ? "[x] " : "[ ] ") + ProfilerTranslations.Text("hide_valheim_callbacks"), Plugin.HideValheimCallbacks.Value ? _activeTabStyle : _tabStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(220f), GUILayout.Height(32f) })) { Plugin.HideValheimCallbacks.Value = !Plugin.HideValheimCallbacks.Value; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.Space(6f); _scroll = GUILayout.BeginScrollView(_scroll, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) }); ProfilerSnapshot snapshot = (((Object)(object)Plugin.Instance == (Object)null) ? null : GetSnapshot()); if (_tab == 0) { DrawSummary(snapshot, ((Rect)(ref _window)).width); } else if (_tab == 1) { DrawMethods(snapshot); } else if (_tab == 2) { DrawGroups(snapshot, _expandedAssemblies, 100); } else if (_tab == 3) { DrawPrefabs(snapshot); } else { DrawVisibleObjects(snapshot); } GUILayout.EndScrollView(); GUILayout.EndVertical(); DrawHoverTooltip(); GUI.DragWindow(new Rect(0f, 0f, Mathf.Max(100f, ((Rect)(ref _window)).width - 76f), 34f)); } private static ProfilerSnapshot GetSnapshot() { if (!((Object)(object)Plugin.Runner == (Object)null)) { return Plugin.Runner.DisplaySnapshot; } return ProfilerCollector.GetLastSnapshot(); } private void DrawToolbar() { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (ProfilerCollector.IsCapturing) { GUILayout.Label(ProfilerTranslations.Text("capturing"), _badStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(125f) }); DrawCaptureTimer(); if (GUILayout.Button(ProfilerTranslations.Text("stop"), _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(165f) })) { Plugin.StopCapture(); } } else { if (GUILayout.Button(ProfilerTranslations.Text("start"), _startButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(165f) })) { Plugin.StartCapture(); } GUILayout.Label(ProfilerTranslations.Format("duration", Plugin.CaptureDurationSeconds.Value), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) }); if (GUILayout.Button("−", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(32f), GUILayout.Height(28f) })) { Plugin.CaptureDurationSeconds.Value = Math.Max(5, Plugin.CaptureDurationSeconds.Value - 5); } if (GUILayout.Button("+", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(32f), GUILayout.Height(28f) })) { Plugin.CaptureDurationSeconds.Value = Math.Min(300, Plugin.CaptureDurationSeconds.Value + 5); } bool flag = Plugin.CaptureLoadedObjects != null && Plugin.CaptureLoadedObjects.Value; string text = (flag ? "[X] " : "[ ] ") + ProfilerTranslations.Text("capture_objects"); GUIStyle val = (flag ? _objectCaptureEnabledStyle : _objectCaptureOptionalStyle); if (GUILayout.Button(text, val, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(250f), GUILayout.Height(32f) }) && Plugin.CaptureLoadedObjects != null) { Plugin.CaptureLoadedObjects.Value = !flag; } } if (GUILayout.Button(ProfilerTranslations.Text("export"), _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) })) { bool flag2 = ProfilerCollector.GetLastSnapshot() != null; string text2 = Plugin.ExportLastReport(); Plugin.NotifyChat((!string.IsNullOrEmpty(text2)) ? ProfilerTranslations.Format("report_saved", Plugin.GetChatReportPath(text2)) : ProfilerTranslations.Text(flag2 ? "report_failed" : "report_no_capture")); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } private static void DrawCaptureTimer() { //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Invalid comparison between Unknown and I4 //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) double num = Math.Max(1.0, ProfilerCollector.DurationLimitSeconds); double num2 = Math.Min(num, Math.Max(0.0, ProfilerCollector.ElapsedSeconds)); float num3 = Mathf.Clamp01((float)(num2 / num)); GUILayout.BeginVertical(_captureTimerPanelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(235f) }); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(ProfilerTranslations.Text("elapsed_short"), _captureTimerLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(88f), GUILayout.Height(16f) }); GUILayout.FlexibleSpace(); GUILayout.Label(FormatCaptureTime(num2) + " / " + FormatCaptureTime(num), _captureTimerValueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(16f) }); GUILayout.EndHorizontal(); Rect rect = GUILayoutUtility.GetRect(1f, 4f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (Event.current != null && (int)Event.current.type == 7) { GUI.DrawTexture(rect, (Texture)(object)_raisedTexture); ((Rect)(ref rect)).width = ((Rect)(ref rect)).width * num3; if (((Rect)(ref rect)).width > 0f) { GUI.DrawTexture(rect, (Texture)(object)_accentTexture); } } GUILayout.EndVertical(); } private static string FormatCaptureTime(double seconds) { int num = (int)Math.Max(0.0, Math.Floor(seconds)); return (num / 60).ToString("00", CultureInfo.InvariantCulture) + ":" + (num % 60).ToString("00", CultureInfo.InvariantCulture); } private static void DrawStatus() { bool isCapturing = ProfilerCollector.IsCapturing; GUILayout.BeginHorizontal(isCapturing ? _badStyle : _surfaceStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("●", isCapturing ? _badStyle : _goodStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(20f) }); GUILayout.Label(ProfilerTranslations.Text(isCapturing ? "active_status" : "ready_status"), _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); } private void DrawTab(int index, string key, float width) { if (GUILayout.Button(ProfilerTranslations.Text(key), (_tab == index) ? _activeTabStyle : _tabStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(width), GUILayout.Height(32f) })) { _tab = index; } } private static void DrawSummary(ProfilerSnapshot snapshot, float windowWidth) { if (snapshot == null) { BeginCard(); GUILayout.Label(ProfilerTranslations.Text("no_report"), _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(ProfilerTranslations.Text("report_directory"), _mutedStyle, Array.Empty<GUILayoutOption>()); EndCard(); DrawLiveServerSummary(windowWidth); DrawLiveObjectSummary(null); return; } float width = Mathf.Max(150f, (windowWidth - 76f) / 3f); ProfilerDataView.GetMethods(snapshot); double frameBudgetPercent = ProfilerDataView.GetFrameBudgetPercent(snapshot); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); DrawMetricCard(ProfilerTranslations.Text("fps"), snapshot.FramesPerSecond.ToString("0.0", CultureInfo.CurrentCulture), ProfilerTranslations.Text("last_capture") + ": " + snapshot.StartedAtUtc.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture), _accentTexture, width); DrawMetricCard(ProfilerTranslations.Text("frame"), snapshot.AverageFrameMilliseconds.ToString("0.00", CultureInfo.CurrentCulture) + " ms", ProfilerTranslations.Text("minmax") + ": " + snapshot.MinFrameMilliseconds.ToString("0.00", CultureInfo.CurrentCulture) + " / " + snapshot.MaxFrameMilliseconds.ToString("0.00", CultureInfo.CurrentCulture), _raisedTexture, width); DrawMetricCard(ProfilerTranslations.Text("callback_share"), frameBudgetPercent.ToString("0.0", CultureInfo.CurrentCulture) + "%", ProfilerTranslations.Text("share_help"), ImpactTexture(frameBudgetPercent), width); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string value = (snapshot.CpuAvailable ? (snapshot.CpuPercentAverage.ToString("0.0", CultureInfo.CurrentCulture) + "% / " + snapshot.CpuPercentMaximum.ToString("0.0", CultureInfo.CurrentCulture) + "%") : "—"); DrawMetricCard(ProfilerTranslations.Text("cpu_process"), value, ProfilerTranslations.Text("avg_peak"), _raisedTexture, width, 136f); string value2 = (snapshot.ProcessRamAvailable ? (FormatMegabytes(snapshot.ProcessRamAverageMegabytes) + " / " + FormatMegabytes(snapshot.ProcessRamMaximumMegabytes)) : "—"); string detail = ProfilerTranslations.Text("managed_heap") + ": " + FormatMegabytes(snapshot.ManagedHeapAverageMegabytes); DrawMetricCard(ProfilerTranslations.Text("ram_process"), value2, detail, _accentTexture, width, 136f); string value3 = (snapshot.GpuUsageAvailable ? (snapshot.GpuUsageAveragePercent.ToString("0.0", CultureInfo.CurrentCulture) + "% / " + snapshot.GpuUsageMaximumPercent.ToString("0.0", CultureInfo.CurrentCulture) + "%") : "—"); string text = (string.IsNullOrEmpty(snapshot.GpuDeviceName) ? string.Empty : snapshot.GpuDeviceName); if (snapshot.GpuMemoryUsedAvailable) { text = text + ((text.Length == 0) ? string.Empty : " · ") + ProfilerTranslations.Text("gpu_vram_used") + ": " + FormatMegabytes(snapshot.GpuMemoryUsedAverageMegabytes) + " / " + FormatMegabytes(snapshot.GpuMemoryUsedMaximumMegabytes); } if (snapshot.GpuMemoryMegabytes > 0) { text = text + ((text.Length == 0) ? string.Empty : " · ") + ProfilerTranslations.Text("gpu_memory") + ": " + FormatMegabytes(snapshot.GpuMemoryMegabytes); } text = text + ((text.Length == 0) ? string.Empty : " · ") + ProfilerTranslations.Text("gpu_frame_time") + ": " + (snapshot.GpuFrameTimingAvailable ? (snapshot.GpuFrameTimeAverageMilliseconds.ToString("0.00", CultureInfo.CurrentCulture) + " / " + snapshot.GpuFrameTimeMaximumMilliseconds.ToString("0.00", CultureInfo.CurrentCulture) + " ms") : ProfilerTranslations.Text("gpu_unavailable")); DrawMetricCard(ProfilerTranslations.Text("gpu_usage"), value3, text, _raisedTexture, width, 136f); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); string value4 = (snapshot.ProcessIoAvailable ? (snapshot.IoReadMegabytes.ToString("0.0", CultureInfo.CurrentCulture) + " / " + snapshot.IoWriteMegabytes.ToString("0.0", CultureInfo.CurrentCulture) + " MB") : "—"); string detail2 = (snapshot.ProcessIoAvailable ? (ProfilerTranslations.Text("read_write_rate") + ": " + snapshot.IoReadRateAverageMegabytesPerSecond.ToString("0.00", CultureInfo.CurrentCulture) + " / " + snapshot.IoWriteRateAverageMegabytesPerSecond.ToString("0.00", CultureInfo.CurrentCulture)) : "—"); DrawMetricCard(ProfilerTranslations.Text("storage_io"), value4, detail2, _raisedTexture, width); ServerTelemetry currentRemoteServerTelemetry = GetCurrentRemoteServerTelemetry(); bool flag = currentRemoteServerTelemetry != null; bool flag2 = snapshot.RemoteServerMetricSamples > 0 || flag; bool flag3 = snapshot.IsServerRuntime && snapshot.FixedUpdatesPerSecondAverage > 0.0; string value5 = ((!flag2) ? (flag3 ? (snapshot.FixedUpdatesPerSecondAverage.ToString("0.0", CultureInfo.CurrentCulture) + " / " + snapshot.FixedUpdatesPerSecondMinimum.ToString("0.0", CultureInfo.CurrentCulture) + " / " + snapshot.FixedUpdatesPerSecondMaximum.ToString("0.0", CultureInfo.CurrentCulture)) : "—") : ((flag && snapshot.RemoteServerMetricSamples <= 0) ? currentRemoteServerTelemetry.FixedUpdatesPerSecond.ToString("0.0", CultureInfo.CurrentCulture) : (snapshot.RemoteServerTicksAverage.ToString("0.0", CultureInfo.CurrentCulture) + " / " + snapshot.RemoteServerTicksMinimum.ToString("0.0", CultureInfo.CurrentCulture) + " / " + snapshot.RemoteServerTicksMaximum.ToString("0.0", CultureInfo.CurrentCulture)))); string detail3 = ((!flag2) ? (flag3 ? ProfilerTranslations.Format("server_detail", snapshot.TargetFixedUpdatesPerSecond.ToString("0.0", CultureInfo.CurrentCulture), snapshot.CpuPercentAverage.ToString("0.0", CultureInfo.CurrentCulture), FormatMegabytes(snapshot.ProcessRamAverageMegabytes)) : GetServerAccessHelp()) : ((flag && snapshot.RemoteServerMetricSamples <= 0) ? ProfilerTranslations.Format("server_detail", currentRemoteServerTelemetry.TargetFixedUpdatesPerSecond.ToString("0.0", CultureInfo.CurrentCulture), currentRemoteServerTelemetry.CpuPercent.ToString("0.0", CultureInfo.CurrentCulture), FormatMegabytes(currentRemoteServerTelemetry.WorkingSetMegabytes)) : ProfilerTranslations.Format("server_detail", snapshot.RemoteServerTargetTicks.ToString("0.0", CultureInfo.CurrentCulture), snapshot.RemoteServerCpuAverage.ToString("0.0", CultureInfo.CurrentCulture), FormatMegabytes(snapshot.RemoteServerRamAverageMegabytes)))); DrawMetricCard(ProfilerTranslations.Text("server_ticks"), value5, detail3, (flag2 || flag3) ? _accentTexture : _raisedTexture, width); DrawMetricCard(ProfilerTranslations.Text("memory"), FormatMegabytes((double)snapshot.ManagedMemoryBefore / 1048576.0) + " → " + FormatMegabytes((double)snapshot.ManagedMemoryAfter / 1048576.0), ProfilerTranslations.Text("gc"), _raisedTexture, width); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); DrawInfoCard(ProfilerTranslations.Text("slow_frames") + ": " + snapshot.SlowFramesOver33Ms.ToString("N0", CultureInfo.CurrentCulture) + " / " + snapshot.SlowFramesOver50Ms.ToString("N0", CultureInfo.CurrentCulture)); DrawInfoCard(ProfilerTranslations.Text("measured_calls") + ": " + ProfilerDataView.GetTotalCalls(snapshot).ToString("N0", CultureInfo.CurrentCulture)); DrawInfoCard(ProfilerTranslations.Text("gc") + ": " + snapshot.Gen0Collections + " / " + snapshot.Gen1Collections + " / " + snapshot.Gen2Collections); GUILayout.EndHorizontal(); DrawLiveObjectSummary(snapshot); GUILayout.Space(8f); GUILayout.Label(ProfilerTranslations.Text("top_callbacks"), _sectionStyle, Array.Empty<GUILayoutOption>()); DrawMethodRows(snapshot, 5); GUILayout.Space(12f); GUILayout.Label(ProfilerTranslations.Text("tab_mods"), _sectionStyle, Array.Empty<GUILayoutOption>()); DrawGroups(snapshot, null, 4); } private static string FormatMegabytes(double megabytes) { if (!(megabytes >= 1024.0)) { return megabytes.ToString("0.0", CultureInfo.CurrentCulture) + " MB"; } return (megabytes / 1024.0).ToString("0.00", CultureInfo.CurrentCulture) + " GB"; } private static void DrawLiveServerSummary(float windowWidth) { ServerTelemetry currentRemoteServerTelemetry = GetCurrentRemoteServerTelemetry(); float width = Mathf.Max(150f, (windowWidth - 76f) / 3f); string value = ((currentRemoteServerTelemetry == null) ? "—" : currentRemoteServerTelemetry.FixedUpdatesPerSecond.ToString("0.0", CultureInfo.CurrentCulture)); string detail = ((currentRemoteServerTelemetry == null) ? GetServerAccessHelp() : ProfilerTranslations.Format("server_detail", currentRemoteServerTelemetry.TargetFixedUpdatesPerSecond.ToString("0.0", CultureInfo.CurrentCulture), currentRemoteServerTelemetry.CpuPercent.ToString("0.0", CultureInfo.CurrentCulture), FormatMegabytes(currentRemoteServerTelemetry.WorkingSetMegabytes))); DrawMetricCard(ProfilerTranslations.Text("server_ticks"), value, detail, (currentRemoteServerTelemetry == null) ? _raisedTexture : _accentTexture, width); } private static ServerTelemetry GetCurrentRemoteServerTelemetry() { ServerTelemetry latest = ServerTelemetryRpc.Latest; if (ServerTelemetryRpc.ServerAdminAccess != true || latest == null) { return null; } if (!(Time.realtimeSinceStartupAsDouble - latest.ReceivedAt <= 8.0)) { return null; } return latest; } private static string GetServerAccessHelp() { if (ServerTelemetryRpc.ServerAdminAccess != false) { return ProfilerTranslations.Text("server_missing"); } return ProfilerTranslations.Text("server_admin_required"); } private static void DrawMethods(ProfilerSnapshot snapshot) { if (snapshot == null) { GUILayout.Label(ProfilerTranslations.Text("no_snapshot"), _mutedStyle, Array.Empty<GUILayoutOption>()); return; } BeginCard(); GUILayout.Label(ProfilerTranslations.Text("exclusive_help"), _mutedStyle, Array.Empty<GUILayoutOption>()); EndCard(); DrawMethodRows(snapshot, 60); } private static void DrawMethodRows(ProfilerSnapshot snapshot, int limit) { List<MethodMetric> list = ((snapshot == null) ? null : ProfilerDataView.GetMethods(snapshot)); if (list == null || list.Count == 0) { GUILayout.Label((snapshot != null && Plugin.HideValheimCallbacks.Value) ? ProfilerTranslations.Text("no_visible_calls") : ProfilerTranslations.Text("no_calls"), _mutedStyle, Array.Empty<GUILayoutOption>()); return; } GUILayout.BeginHorizontal(_headerStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(30f) }); GUILayout.Label(ProfilerTranslations.Text("callback_type"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(280f) }); GUILayout.Label(ProfilerTranslations.Text("assembly"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }); GUILayout.Label(ProfilerTranslations.Text("calls"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label(ProfilerTranslations.Text("self_ms"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(75f) }); GUILayout.Label(ProfilerTranslations.Text("per_frame"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label(ProfilerTranslations.Text("budget"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(ProfilerTranslations.Text("average"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUILayout.Label(ProfilerTranslations.Text("maximum"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(65f) }); GUILayout.EndHorizontal(); int num = Math.Min(limit, list.Count); for (int i = 0; i < num; i++) { MethodMetric methodMetric = list[i]; GUILayout.BeginHorizontal((i % 2 == 0) ? _rowStyle : _alternateRowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }); GUILayout.Label(TruncatedContent(methodMetric.Label, 42), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(280f) }); GUILayout.Label(TruncatedContent(methodMetric.AssemblyName, 19), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(140f) }); GUILayout.Label(methodMetric.Calls.ToString("N0", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.Label(methodMetric.SelfMilliseconds.ToString("0.00", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(75f) }); GUILayout.Label(methodMetric.AverageFrameShareMilliseconds(snapshot).ToString("0.000", CultureInfo.CurrentCulture), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); double percent = methodMetric.FrameBudgetPercent(snapshot); GUILayout.Label(percent.ToString("0.0", CultureInfo.CurrentCulture) + "%", ImpactStyle(percent), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(methodMetric.AverageMilliseconds.ToString("0.000", CultureInfo.CurrentCulture), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUILayout.Label(methodMetric.MaxMilliseconds.ToString("0.00", CultureInfo.CurrentCulture), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(65f) }); GUILayout.EndHorizontal(); } } private static void DrawPrefabs(ProfilerSnapshot snapshot) { if (snapshot == null) { GUILayout.Label(ProfilerTranslations.Text("no_snapshot"), _mutedStyle, Array.Empty<GUILayoutOption>()); return; } BeginCard(); GUILayout.Label(ProfilerTranslations.Text("components_help"), _mutedStyle, Array.Empty<GUILayoutOption>()); EndCard(); DrawPrefabRows(snapshot, 60); GUILayout.Space(12f); GUILayout.Label(ProfilerTranslations.Text("individual_instances"), _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(_headerStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(ProfilerTranslations.Text("object_component"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(430f) }); GUILayout.Label(ProfilerTranslations.Text("assembly"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label(ProfilerTranslations.Text("calls"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(ProfilerTranslations.Text("self_ms"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.EndHorizontal(); List<ObjectMetric> objects = ProfilerDataView.GetObjects(snapshot); int num = Math.Min(40, objects.Count); for (int i = 0; i < num; i++) { ObjectMetric objectMetric = objects[i]; GUILayout.BeginHorizontal((i % 2 == 0) ? _rowStyle : _alternateRowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }); GUILayout.Label(TruncatedContent(objectMetric.ObjectName + " • " + objectMetric.ComponentType, 64), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(430f) }); GUILayout.Label(TruncatedContent(objectMetric.AssemblyName, 20), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label(objectMetric.Calls.ToString("N0", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(objectMetric.SelfMilliseconds.ToString("0.00", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.EndHorizontal(); } } private void DrawVisibleObjects(ProfilerSnapshot snapshot) { VisibleObjectScan latest = VisibleObjectScanner.Latest; bool flag = latest?.Available ?? false; if ((snapshot == null || !snapshot.VisibleObjectScanAvailable) && !flag) { BeginCard(); GUILayout.Label(ProfilerTranslations.Text((!ProfilerCollector.IsCapturing || !Plugin.IncludeLoadedObjectsInCurrentCapture) ? "object_scan_policy" : ((latest == null) ? "object_scan_pending" : "visible_unavailable")), _mutedStyle, Array.Empty<GUILayoutOption>()); EndCard(); return; } List<VisibleObjectMetric> visibleObjectsForHud = ProfilerDataView.GetVisibleObjectsForHud(snapshot, latest); int objectCount = SumVisibleObjectQuantities(visibleObjectsForHud); BeginCard(); GUILayout.Label(FormatObjectCountSummary(objectCount), _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(ProfilerTranslations.Text("visible_help"), _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(ProfilerTranslations.Text("object_scan_policy"), _mutedStyle, Array.Empty<GUILayoutOption>()); EndCard(); if (visibleObjectsForHud.Count == 0) { GUILayout.Label(ProfilerTranslations.Text("no_visible_objects"), _mutedStyle, Array.Empty<GUILayoutOption>()); return; } GUILayout.BeginHorizontal(_headerStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(ProfilerTranslations.Text("object_component"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(430f) }); GUILayout.Label(ProfilerTranslations.Text("assembly"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(210f) }); GUILayout.Label(ProfilerTranslations.Text("quantity"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(105f) }); GUILayout.EndHorizontal(); int num = Math.Max(1, (visibleObjectsForHud.Count + 50 - 1) / 50); _visibleObjectsPage = Mathf.Clamp(_visibleObjectsPage, 0, num - 1); int num2 = _visibleObjectsPage * 50; int num3 = Math.Min(visibleObjectsForHud.Count, num2 + 50); for (int i = num2; i < num3; i++) { VisibleObjectMetric visibleObjectMetric = visibleObjectsForHud[i]; string visibleObjectKey = GetVisibleObjectKey(visibleObjectMetric); bool flag2 = string.Equals(_expandedVisibleObjectKey, visibleObjectKey, StringComparison.Ordinal); GUILayout.BeginHorizontal(((i - num2) % 2 == 0) ? _rowStyle : _alternateRowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }); if (GUILayout.Button(flag2 ? "▾" : "▸", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(28f), GUILayout.Height(23f) })) { _expandedVisibleObjectKey = (flag2 ? null : visibleObjectKey); _visibleObjectIdsPage = 0; } GUILayout.Label(TruncatedContent(visibleObjectMetric.ObjectName, 54), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(402f) }); GUILayout.Label(TruncatedContent(ProfilerDataView.IsVanillaAssembly(visibleObjectMetric.AssemblyName) ? ProfilerTranslations.Text("vanilla_game") : visibleObjectMetric.AssemblyName, 30), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(210f) }); GUILayout.Label(visibleObjectMetric.CurrentInstances.ToString("N0", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(105f) }); GUILayout.EndHorizontal(); if (flag2) { DrawVisibleObjectIds(visibleObjectMetric, i - num2); } } if (num > 1) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); if (GUILayout.Button("‹", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(34f), GUILayout.Height(27f) })) { _visibleObjectsPage = Math.Max(0, _visibleObjectsPage - 1); } GUILayout.Label((_visibleObjectsPage + 1).ToString(CultureInfo.CurrentCulture) + " / " + num.ToString(CultureInfo.CurrentCulture), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(70f), GUILayout.Height(27f) }); if (GUILayout.Button("›", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(34f), GUILayout.Height(27f) })) { _visibleObjectsPage = Math.Min(num - 1, _visibleObjectsPage + 1); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } } private static void DrawLiveObjectSummary(ProfilerSnapshot snapshot) { VisibleObjectScan latest = VisibleObjectScanner.Latest; if (latest != null && latest.Available) { int objectCount = SumVisibleObjectQuantities(ProfilerDataView.GetVisibleObjectsForHud(snapshot, latest)); BeginCard(); GUILayout.Label(FormatObjectCountSummary(objectCount), _labelStyle, Array.Empty<GUILayoutOption>()); EndCard(); } } private static string FormatObjectCountSummary(int objectCount) { return ProfilerTranslations.Text("tab_visible_objects") + ": " + objectCount.ToString("N0", CultureInfo.CurrentCulture); } private static int SumVisibleObjectQuantities(List<VisibleObjectMetric> objects) { int num = 0; for (int i = 0; i < objects.Count; i++) { num += objects[i].CurrentInstances; } return num; } private static string GetVisibleObjectKey(VisibleObjectMetric metric) { return metric.Key ?? ((metric.AssemblyName ?? string.Empty) + "\0" + (metric.ObjectName ?? string.Empty)); } private void DrawVisibleObjectIds(VisibleObjectMetric metric, int rowIndex) { List<int> instanceIds = metric.InstanceIds; if (instanceIds == null || instanceIds.Count == 0) { return; } int num = Math.Max(1, (instanceIds.Count + 30 - 1) / 30); _visibleObjectIdsPage = Mathf.Clamp(_visibleObjectIdsPage, 0, num - 1); int num2 = _visibleObjectIdsPage * 30; int num3 = Math.Min(instanceIds.Count, num2 + 30); StringBuilder stringBuilder = new StringBuilder((num3 - num2) * 12); for (int i = num2; i < num3; i++) { if (i > num2) { stringBuilder.Append(", "); } stringBuilder.Append(instanceIds[i].ToString(CultureInfo.InvariantCulture)); } GUILayout.BeginHorizontal((rowIndex % 2 == 0) ? _rowStyle : _alternateRowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(28f) }); GUILayout.Space(28f); GUILayout.Label(ProfilerTranslations.Text("object_ids") + ": " + stringBuilder, _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); if (num > 1) { if (GUILayout.Button("‹", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(28f), GUILayout.Height(24f) })) { _visibleObjectIdsPage = Math.Max(0, _visibleObjectIdsPage - 1); } GUILayout.Label((_visibleObjectIdsPage + 1).ToString(CultureInfo.CurrentCulture) + " / " + num.ToString(CultureInfo.CurrentCulture), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(54f) }); if (GUILayout.Button("›", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(28f), GUILayout.Height(24f) })) { _visibleObjectIdsPage = Math.Min(num - 1, _visibleObjectIdsPage + 1); } } GUILayout.EndHorizontal(); } private static void DrawPrefabRows(ProfilerSnapshot snapshot, int limit) { List<PrefabMetric> list = ((snapshot == null) ? null : ProfilerDataView.GetPrefabs(snapshot)); if (list == null || list.Count == 0) { GUILayout.Label(ProfilerTranslations.Text("no_components"), _mutedStyle, Array.Empty<GUILayoutOption>()); return; } GUILayout.BeginHorizontal(_headerStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(ProfilerTranslations.Text("object_component"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(430f) }); GUILayout.Label(ProfilerTranslations.Text("assembly"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label(ProfilerTranslations.Text("instances"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(ProfilerTranslations.Text("calls"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(ProfilerTranslations.Text("self_ms"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.EndHorizontal(); int num = Math.Min(limit, list.Count); for (int i = 0; i < num; i++) { PrefabMetric prefabMetric = list[i]; GUILayout.BeginHorizontal((i % 2 == 0) ? _rowStyle : _alternateRowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }); GUILayout.Label(TruncatedContent(prefabMetric.ObjectName + " • " + prefabMetric.ComponentType, 64), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(430f) }); GUILayout.Label(TruncatedContent(prefabMetric.AssemblyName, 20), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label(prefabMetric.Instances.ToString("N0", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(prefabMetric.Calls.ToString("N0", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.Label(prefabMetric.SelfMilliseconds.ToString("0.00", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }); GUILayout.EndHorizontal(); } } private static void DrawMetricCard(string title, string value, string detail, Texture2D accent, float width, float minimumHeight = 110f) { GUILayout.BeginVertical(((Object)(object)accent == (Object)(object)_badTexture) ? _badCardStyle : (((Object)(object)accent == (Object)(object)_warnTexture) ? _warnCardStyle : (((Object)(object)accent == (Object)(object)_goodTexture) ? _goodCardStyle : (((Object)(object)accent == (Object)(object)_raisedTexture) ? _surfaceStyle : _accentCardStyle))), (GUILayoutOption[])(object)new GUILayoutOption[3] { GUILayout.Width(width), GUILayout.MinHeight(minimumHeight), GUILayout.ExpandHeight(true) }); GUILayout.Label(title, _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(value, _metricStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(detail, _mutedStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); } private static void DrawInfoCard(string text) { GUILayout.BeginVertical(_surfaceStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.MinHeight(40f) }); GUILayout.Label(text, _labelStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndVertical(); } private static void BeginCard() { GUILayout.BeginVertical(_surfaceStyle, Array.Empty<GUILayoutOption>()); } private static void EndCard() { GUILayout.EndVertical(); } private static GUIStyle ImpactStyle(double percent) { if (percent >= 25.0) { return _badStyle; } if (percent >= 10.0) { return _warnStyle; } return _goodStyle; } private static void DrawGroups(ProfilerSnapshot snapshot, HashSet<string> expanded, int limit) { if (snapshot == null) { GUILayout.Label(ProfilerTranslations.Text("no_snapshot"), _mutedStyle, Array.Empty<GUILayoutOption>()); return; } List<AssemblyGroupMetric> groups = ProfilerDataView.GetGroups(snapshot); if (groups.Count == 0) { GUILayout.Label(ProfilerDataView.HideVanilla ? ProfilerTranslations.Text("no_visible_calls") : ProfilerTranslations.Text("no_calls"), _mutedStyle, Array.Empty<GUILayoutOption>()); return; } GUILayout.BeginHorizontal(_headerStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinHeight(30f) }); GUILayout.Label(ProfilerTranslations.Text("mod_or_game"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(410f) }); GUILayout.Label(ProfilerTranslations.Text("calls"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(115f) }); GUILayout.Label(ProfilerTranslations.Text("self_ms"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(115f) }); GUILayout.Label(ProfilerTranslations.Text("budget"), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(135f) }); GUILayout.EndHorizontal(); int num = ((expanded == null) ? limit : 50); int num2 = Math.Max(1, (groups.Count + num - 1) / num); if (expanded != null) { _modsPage = Mathf.Clamp(_modsPage, 0, num2 - 1); } int num3 = ((expanded != null) ? (_modsPage * num) : 0); int num4 = Math.Min(groups.Count, num3 + num); int num5 = 50; for (int i = num3; i < num4; i++) { AssemblyGroupMetric assemblyGroupMetric = groups[i]; bool flag = expanded?.Contains(assemblyGroupMetric.Key) ?? false; GUILayout.BeginHorizontal(((i - num3) % 2 == 0) ? _rowStyle : _alternateRowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(31f) }); if (expanded != null && GUILayout.Button((flag ? "▾ " : "▸ ") + GroupDisplayName(assemblyGroupMetric), _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(410f), GUILayout.Height(27f) })) { if (flag) { expanded.Remove(assemblyGroupMetric.Key); ExpandedMethodPages.Remove(assemblyGroupMetric.Key); } else { expanded.Clear(); ExpandedMethodPages.Clear(); expanded.Add(assemblyGroupMetric.Key); } } else if (expanded == null) { GUILayout.Label("• " + GroupDisplayName(assemblyGroupMetric), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(410f) }); } GUILayout.Label(assemblyGroupMetric.Calls.ToString("N0", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(115f) }); GUILayout.Label(assemblyGroupMetric.SelfMilliseconds.ToString("0.00", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(115f) }); double percent = assemblyGroupMetric.FrameBudgetPercent(snapshot); GUILayout.Label(percent.ToString("0.0", CultureInfo.CurrentCulture) + "%", ImpactStyle(percent), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(135f) }); GUILayout.EndHorizontal(); if (!flag) { continue; } int num6 = Math.Max(1, (assemblyGroupMetric.Methods.Count + 50 - 1) / 50); ExpandedMethodPages.TryGetValue(assemblyGroupMetric.Key, out var value); value = Mathf.Clamp(value, 0, num6 - 1); ExpandedMethodPages[assemblyGroupMetric.Key] = value; int num7 = value * 50; int num8 = Math.Min(assemblyGroupMetric.Methods.Count, num7 + Math.Min(50, num5)); for (int j = num7; j < num8; j++) { MethodMetric methodMetric = assemblyGroupMetric.Methods[j]; GUILayout.BeginHorizontal(((j - num7) % 2 == 0) ? _rowStyle : _alternateRowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }); GUILayout.Space(24f); GUILayout.Label(TruncatedContent(methodMetric.Label, 54), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(386f) }); GUILayout.Label(methodMetric.Calls.ToString("N0", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(115f) }); GUILayout.Label(methodMetric.SelfMilliseconds.ToString("0.00", CultureInfo.CurrentCulture), _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(115f) }); double percent2 = methodMetric.FrameBudgetPercent(snapshot); GUILayout.Label(percent2.ToString("0.0", CultureInfo.CurrentCulture) + "%", ImpactStyle(percent2), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(135f) }); GUILayout.EndHorizontal(); } num5 -= num8 - num7; if (num6 > 1) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Space(24f); if (GUILayout.Button("‹", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(30f), GUILayout.Height(25f) })) { ExpandedMethodPages[assemblyGroupMetric.Key] = Math.Max(0, value - 1); } GUILayout.Label((value + 1).ToString(CultureInfo.CurrentCulture) + " / " + num6.ToString(CultureInfo.CurrentCulture), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(70f), GUILayout.Height(25f) }); if (GUILayout.Button("›", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(30f), GUILayout.Height(25f) })) { ExpandedMethodPages[assemblyGroupMetric.Key] = Math.Min(num6 - 1, value + 1); } GUILayout.EndHorizontal(); } } if (expanded != null && num2 > 1) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); if (GUILayout.Button("‹", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(34f), GUILayout.Height(27f) })) { _modsPage = Math.Max(0, _modsPage - 1); } GUILayout.Label((_modsPage + 1).ToString(CultureInfo.CurrentCulture) + " / " + num2.ToString(CultureInfo.CurrentCulture), _mutedStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(70f), GUILayout.Height(27f) }); if (GUILayout.Button("›", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(34f), GUILayout.Height(27f) })) { _modsPage = Math.Min(num2 - 1, _modsPage + 1); } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } } private static string GroupDisplayName(AssemblyGroupMetric group) { if (!group.IsVanilla) { return group.AssemblyName; } return ProfilerTranslations.Text("vanilla_game"); } private static Texture2D ImpactTexture(double percent) { if (percent >= 25.0) { return _badTexture; } if (percent >= 10.0) { return _warnTexture; } return _goodTexture; } private static string Shorten(string value, int maxLength) { if (string.IsNullOrEmpty(value) || value.Length <= maxLength) { return value ?? string.Empty; } return "…" + value.Substring(value.Length - maxLength + 1); } private static GUIContent TruncatedContent(string value, int maxLength) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown string text = value ?? string.Empty; if (text.Length <= maxLength) { return new GUIContent(text); } return new GUIContent(Shorten(text, maxLength), text); } private void DrawHoverTooltip() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (Event.current != null && (int)Event.current.type == 7 && !string.IsNullOrEmpty(GUI.tooltip)) { string tooltip = GUI.tooltip; float num = Mathf.Max(180f, Mathf.Min(460f, ((Rect)(ref _window)).width - 28f)); GUIContent val = new GUIContent(tooltip); Vector2 val2 = _tooltipStyle.CalcSize(val); float num2 = Mathf.Min(num, Mathf.Max(180f, val2.x + (float)_tooltipStyle.padding.horizontal)); float num3 = Mathf.Min(240f, _tooltipStyle.CalcHeight(val, num2)); Vector2 mousePosition = Event.current.mousePosition; float num4 = mousePosition.x + 16f; float num5 = mousePosition.y + 18f; if (num4 + num2 > ((Rect)(ref _window)).width - 8f) { num4 = mousePosition.x - num2 - 12f; } if (num5 + num3 > ((Rect)(ref _window)).height - 8f) { num5 = mousePosition.y - num3 - 12f; } num4 = Mathf.Clamp(num4, 8f, Mathf.Max(8f, ((Rect)(ref _window)).width - num2 - 8f)); num5 = Mathf.Clamp(num5, 8f, Mathf.Max(8f, ((Rect)(ref _window)).height - num3 - 8f)); GUI.Box(new Rect(num4, num5, num2, num3), val, _tooltipStyle); } } private static void EnsureStyles() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Expected O, but got Unknown //IL_01dd: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Expected O, but got Unknown //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Expected O, but got Unknown //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Expected O, but got Unknown //IL_0486: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Expected O, but got Unknown //IL_049a: Expected O, but got Unknown //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_0509: Unknown result type (might be due to invalid IL or missing references) //IL_0513: Expected O, but got Unknown //IL_052c: Unknown result type (might be due to invalid IL or missing references) //IL_0531: Unknown result type (might be due to invalid IL or missing references) //IL_0555: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Expected O, but got Unknown //IL_0564: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_0591: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_05cd: Unknown result type (might be due to invalid IL or missing references) //IL_05d2: Unknown result type (might be due to invalid IL or missing references) //IL_05fa: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Unknown result type (might be due to invalid IL or missing references) //IL_0627: Unknown result type (might be due to invalid IL or missing references) //IL_062c: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_0659: Unknown result type (might be due to invalid IL or missing references) if (_windowStyle == null) { _windowTexture = Pixel(Color32.op_Implicit(new Color32((byte)16, (byte)22, (byte)30, byte.MaxValue))); _surfaceTexture = Pixel(Color32.op_Implicit(new Color32((byte)27, (byte)37, (byte)49, byte.MaxValue))); _raisedTexture = Pixel(Color32.op_Implicit(new Color32((byte)34, (byte)48, (byte)63, byte.MaxValue))); _headerTexture = Pixel(Color32.op_Implicit(new Color32((byte)25, (byte)44, (byte)61, byte.MaxValue))); _stripeTexture = Pixel(Color32.op_Implicit(new Color32((byte)22, (byte)30, (byte)40, byte.MaxValue))); _accentTexture = Pixel(Color32.op_Implicit(new Color32((byte)35, (byte)91, (byte)119, byte.MaxValue))); _goodTexture = Pixel(Color32.op_Implicit(new Color32((byte)31, (byte)91, (byte)71, byte.MaxValue))); _warnTexture = Pixel(Color32.op_Implicit(new Color32((byte)127, (byte)85, (byte)24, byte.MaxValue))); _badTexture = Pixel(Color32.op_Implicit(new Color32((byte)128, (byte)48, (byte)47, byte.MaxValue))); _buttonHoverTexture = Pixel(Color32.op_Implicit(new Color32((byte)47, (byte)102, (byte)128, byte.MaxValue))); _buttonPressedTexture = Pixel(Color32.op_Implicit(new Color32((byte)25, (byte)60, (byte)79, byte.MaxValue))); GUIStyle val = new GUIStyle(GUI.skin.window); val.normal.background = _windowTexture; val.normal.textColor = Color.white; val.onNormal.background = _windowTexture; val.onNormal.textColor = Color.white; val.border = new RectOffset(10, 10, 10, 10); val.padding = new RectOffset(14, 14, 10, 12); _windowStyle = val; _surfaceStyle = BoxStyle(_surfaceTexture, 10, 10, 7, 7); _accentCardStyle = BoxStyle(_accentTexture, 10, 10, 7, 7); _goodCardStyle = BoxStyle(_goodTexture, 10, 10, 7, 7); _warnCardStyle = BoxStyle(_warnTexture, 10, 10, 7, 7); _badCardStyle = BoxStyle(_badTexture, 10, 10, 7, 7); _headerStyle = BoxStyle(_headerTexture, 8, 8, 5, 5); _rowStyle = BoxStyle(_surfaceTexture, 6, 6, 2, 2); _alternateRowStyle = BoxStyle(_stripeTexture, 6, 6, 2, 2); _labelStyle = LabelStyle(Color32.op_Implicit(new Color32((byte)239, (byte)244, (byte)249, byte.MaxValue)), 14, (FontStyle)0); _mutedStyle = LabelStyle(Color32.op_Implicit(new Color32((byte)174, (byte)190, (byte)205, byte.MaxValue)), 13, (FontStyle)0); _titleStyle = LabelStyle(Color32.op_Implicit(new Color32((byte)240, (byte)247, (byte)252, byte.MaxValue)), 18, (FontStyle)1); _sectionStyle = LabelStyle(Color32.op_Implicit(new Color32((byte)100, (byte)205, (byte)223, byte.MaxValue)), 16, (FontStyle)1); _metricStyle = LabelStyle(Color32.op_Implicit(new Color32((byte)249, (byte)252, byte.MaxValue, byte.MaxValue)), 23, (FontStyle)1); _captureTimerPanelStyle = BoxStyle(_surfaceTexture, 8, 8, 2, 2); GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 11, fontStyle = (FontStyle)1, alignment = (TextAnchor)3, wordWrap = false }; val2.normal.textColor = Color32.op_Implicit(new Color32((byte)112, (byte)198, (byte)218, byte.MaxValue)); _captureTimerLabelStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 14, fontStyle = (FontStyle)1, alignment = (TextAnchor)5, wordWrap = false }; val3.normal.textColor = Color32.op_Implicit(new Color32((byte)242, (byte)247, (byte)252, byte.MaxValue)); _captureTimerValueStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.box); val4.normal.background = _headerTexture; val4.normal.textColor = Color32.op_Implicit(new Color32((byte)245, (byte)249, (byte)252, byte.MaxValue)); val4.alignment = (TextAnchor)0; val4.wordWrap = true; val4.fontSize = 13; val4.padding = new RectOffset(10, 10, 7, 7); val4.border = new RectOffset(8, 8, 8, 8); _tooltipStyle = val4; _buttonStyle = ButtonStyle(_raisedTexture, Color32.op_Implicit(new Color32((byte)244, (byte)247, (byte)250, byte.MaxValue))); _objectCaptureOptionalStyle = ButtonStyle(_warnTexture, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)238, (byte)192, byte.MaxValue))); _objectCaptureOptionalStyle.fontSize = 12; _objectCaptureOptionalStyle.padding = new RectOffset(5, 5, 4, 4); _objectCaptureEnabledStyle = ButtonStyle(_goodTexture, Color32.op_Implicit(new Color32((byte)207, byte.MaxValue, (byte)226, byte.MaxValue))); _objectCaptureEnabledStyle.fontSize = 12; _objectCaptureEnabledStyle.padding = new RectOffset(5, 5, 4, 4); _startButtonStyle = ButtonStyle(_accentTexture, Color.white); _tabStyle = ButtonStyle(_surfaceTexture, Color32.op_Implicit(new Color32((byte)190, (byte)205, (byte)218, byte.MaxValue))); _activeTabStyle = ButtonStyle(_accentTexture, Color.white); _goodStyle = ButtonStyle(_goodTexture, Color32.op_Implicit(new Color32((byte)207, byte.MaxValue, (byte)226, byte.MaxValue))); _warnStyle = ButtonStyle(_warnTexture, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)238, (byte)192, byte.MaxValue))); _badStyle = ButtonStyle(_badTexture, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)214, (byte)207, byte.MaxValue))); _closeButtonStyle = ButtonStyle(_surfaceTexture, Color32.op_Implicit(new Color32((byte)238, (byte)245, (byte)251, byte.MaxValue))); } } private static GUIStyle BoxStyle(Texture2D texture, int left, int right, int top, int bottom) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_005a: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.box); val.normal.background = texture; val.normal.textColor = Color.white; val.padding = new RectOffset(left, right, top, bottom); val.margin = new RectOffset(2, 2, 2, 2); val.border = new RectOffset(5, 5, 5, 5); return val; } private static GUIStyle ButtonStyle(Texture2D texture, Color textColor) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.button) { fontSize = 14, fontStyle = (FontStyle)1, padding = new RectOffset(9, 9, 6, 6) }; val.normal.background = texture; val.normal.textColor = textColor; val.hover.background = _buttonHoverTexture; val.hover.textColor = Color.white; val.active.background = _buttonPressedTexture; val.active.textColor = Color.white; val.focused.background = texture; val.focused.textColor = Color.white; return val; } private static GUIStyle LabelStyle(Color color, int size, FontStyle weight) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = size, fontStyle = weight, wordWrap = true }; val.normal.textColor = color; val.hover.textColor = color; return val; } private static Texture2D Pixel(Color color) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false) { hideFlags = (HideFlags)61, filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1 }; val.SetPixel(0, 0, color); val.Apply(false, true); return val; } private void OnDestroy() { DestroyTexture(_windowTexture); DestroyTexture(_surfaceTexture); DestroyTexture(_raisedTexture); DestroyTexture(_headerTexture); DestroyTexture(_stripeTexture); DestroyTexture(_accentTexture); DestroyTexture(_goodTexture); DestroyTexture(_warnTexture); DestroyTexture(_badTexture); DestroyTexture(_buttonHoverTexture); DestroyTexture(_buttonPressedTexture); _windowStyle = null; } private static void DestroyTexture(Texture2D texture) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } } internal static class PerformanceReporter { internal static string Export(ProfilerSnapshot snapshot) { if (snapshot == null) { return null; } try { string text = Path.Combine(Paths.ConfigPath, "ValheimPerformanceAnalyzer", "Reports"); Directory.CreateDirectory(text); string path = "Valheim-Profile-" + snapshot.StartedAtUtc.ToLocalTime().ToString("yyyyMMdd-HHmmss-fff", CultureInfo.InvariantCulture); string text2 = Path.Combine(text, path); Directory.CreateDirectory(text2); string text3 = Path.Combine(text2, "index.html"); File.WriteAllText(text3, BuildHtml(snapshot), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); return text3; } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("Falha ao salvar o relatório do profiler: " + ex)); } return null; } } private static string BuildHtml(ProfilerSnapshot snapshot) { CultureInfo numberCulture = ProfilerTranslations.NumberCulture; List<AssemblyGroupMetric> groups = ProfilerDataView.GetGroups(snapshot); List<PrefabMetric> prefabs = ProfilerDataView.GetPrefabs(snapshot); List<ObjectMetric> objects = ProfilerDataView.GetObjects(snapshot); List<VisibleObjectMetric> visibleObjects = ProfilerDataView.GetVisibleObjects(snapshot); double totalSelfMilliseconds = ProfilerDataView.GetTotalSelfMilliseconds(snapshot); StringBuilder stringBuilder = new StringBuilder(30000); stringBuilder.AppendLine("<!doctype html>"); stringBuilder.Append("<html lang=\"").Append(Html(numberCulture.Name)).AppendLine("\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"); stringBuilder.Append("<title>").Append(Html("Valheim Performance Analyzer")).AppendLine("</title>"); stringBuilder.AppendLine("<style>"); stringBuilder.AppendLine("* { box-sizing: border-box; }\nbody { margin: 0; background: #0d141c; color: #e7eef5; font: 15px/1.45 Segoe UI, Arial, sans-serif; }\nmain { max-width: 1500px; margin: auto; padding: 24px; }\nh1 { margin: 0 0 8px; color: #f4f8fb; font-size: 25px; }\nh2 { margin: 30px 0 10px; color: #55c4df; font-size: 19px; }\n.hint { margin: 0 0 20px; color: #aebecd; }\n.toolbar { padding: 10px 0; background: #0d141c; }\ninput { width: min(420px, 100%); padding: 9px 12px; border: 1px solid #405163; border-radius: 4px; background: #1b2531; color: #eef5fb; }\n.summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; }\n.card { min-height: 80px; padding: 12px 14px; border-left: 3px solid #2686a5; background: #1b2531; }\n.card b { display: block; color: #9bb2c6; font-size: 13px; font-weight: 500; }\n.card strong { display: block; margin-top: 3px; font-size: 22px; }\n.card small { color: #93a9bd; }\n.table-wrap { overflow: auto; border: 1px solid #263545; }\ntable { width: 100%; min-width: 760px; border-collapse: collapse; background: #131c26; }\nth, td { padding: 9px 11px; border-bottom: 1px solid #2b3948; text-align: left; vertical-align: top; }\nth { background: #1a3042; color: #dce9f3; user-select: none; cursor: pointer; white-space: nowrap; }\nth:hover { background: #28536c; }\nth[draggable=true] { cursor: grab; }\nth[draggable=true]:active { cursor: grabbing; }\ntbody tr:nth-child(even) { background: #19232e; }\ntbody tr:hover { background: #202d3a; }\n.number { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }\n.good { color: #8af0b7; }\n.warn { color: #ffd779; }\n.bad { color: #ffaaa1; }\ndetails > summary { color: #e9f2f9; font-weight: 600; cursor: pointer; }\ndetails > summary:hover { color: #55c4df; }\n.nested { max-width: 1200px; margin-top: 12px; }\n.nested table { min-width: 740px; font-size: 13px; }\n.empty { padding: 14px; color: #aebecd; }\n.foot { margin: 24px 0 8px; color: #8298ab; font-size: 13px; }\n@media (max-width: 700px) {\n main { padding: 12px; }\n h1 { font-size: 21px; }\n .summary { grid-template-columns: 1fr 1fr; }\n}"); stringBuilder.AppendLine("</style></head><body><main>"); stringBuilder.Append("<h1>").Append(Html("Valheim Performance Analyzer")).AppendLine("</h1>"); stringBuilder.Append("<p class=\"hint\">").Append(Html(ProfilerTranslations.Text("report_table_help"))).AppendLine("</p>"); stringBuilder.Append("<div class=\"toolbar\"><input id=\"filter\" type=\"search\" placeholder=\"").Append(Html(ProfilerTranslations.Text("report_search"))).AppendLine("\"></div>"); stringBuilder.Append("<h2>").Append(Html(ProfilerTranslations.Text("tab_summary"))).AppendLine("</h2><div class=\"summary\">"); Card(stringBuilder, ProfilerTranslations.Text("last_capture"), snapshot.StartedAtUtc.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss", numberCulture)); Card(stringBuilder, ProfilerTranslations.Text("duration_label"), snapshot.DurationSeconds.ToString("0.0", numberCulture) + " s"); Card(stringBuilder, ProfilerTranslations.Text("fps"), Format(snapshot.FramesPerSecond)); Card(stringBuilder, ProfilerTranslations.Text("frame"), Format(snapshot.AverageFrameMilliseconds) + " ms (" + ProfilerTranslations.Text("minmax") + ": " + Format(snapshot.MinFrameMilliseconds) + " / " + Format(snapshot.MaxFrameMilliseconds) + ")"); Card(stringBuilder, ProfilerTranslations.Text("callback_share"), Format(ProfilerDataView.GetFrameBudgetPercent(snapshot)) + "%", ProfilerTranslations.Text("share_help")); Card(stringBuilder, ProfilerTranslations.Text("measured_calls"), ProfilerDataView.GetTotalCalls(snapshot).ToString("N0", numberCulture)); Card(stringBuilder, ProfilerTranslations.Text("slow_frames"), snapshot.SlowFramesOver33Ms.ToString("N0", numberCulture) + " / " + snapshot.SlowFramesOver50Ms.ToString("N0", numberCulture)); Card(stringBuilder, ProfilerTranslations.Text("memory"), Format((double)snapshot.ManagedMemoryBefore / 1048576.0) + " → " + Format((double)snapshot.ManagedMemoryAfter / 1048576.0) + " MB"); Card(stringBuilder, ProfilerTranslations.Text("gc"), snapshot.Gen0Collections + " / " + snapshot.Gen1Collections + " / " + snapshot.Gen2Collections); Card(stringBuilder, ProfilerTranslations.Text("cpu_process"), snapshot.CpuAvailable ? (Format(snapshot.CpuPercentAverage) + "% / " + Format(snapshot.CpuPercentMaximum) + "%") : "—", ProfilerTranslations.Text("avg_peak")); Card(stringBuilder, ProfilerTranslations.Text("ram_process"), snapshot.ProcessRamAvailable ? (FormatMemory(snapshot.ProcessRamAverageMegabytes) + " / " + FormatMemory(snapshot.ProcessRamMaximumMegabytes)) : "—", ProfilerTranslations.Text("managed_heap") + ": " + FormatMemory(snapshot.ManagedHeapAverageMegabytes)); string value = (snapshot.GpuUsageAvailable ? (Format(snapshot.GpuUsageAveragePercent) + "% / " + Format(snapshot.GpuUsageMaximumPercent) + "%") : "—"); string text = snapshot.GpuDeviceName; if (snapshot.GpuMemoryUsedAvailable) { text = text + ((text.Length == 0) ? string.Empty : " · ") + ProfilerTranslations.Text("gpu_vram_used") + ": " + FormatMemory(snapshot.GpuMemoryUsedAverageMegabytes) + " / " + FormatMemory(snapshot.GpuMemoryUsedMaximumMegabytes); } if (snapshot.GpuMemoryMegabytes > 0) { text = text + ((text.Length == 0) ? string.Empty : " · ") + ProfilerTranslations.Text("gpu_memory") + ": " + FormatMemory(snapshot.GpuMemoryMegabytes); } text = text + ((text.Length == 0) ? string.Empty : " · ") + ProfilerTranslations.Text("gpu_frame_time") + ": " + (snapshot.GpuFrameTimingAvailable ? (Format(snapshot.GpuFrameTimeAverageMilliseconds) + " / " + Format(snapshot.GpuFrameTimeMaximumMilliseconds) + " ms") : ProfilerTranslations.Text("gpu_unavailable")); Card(stringBuilder, ProfilerTranslations.Text("gpu_usage"), value, text); string value2 = (snapshot.ProcessIoAvailable ? (Format(snapshot.IoReadMegabytes) + " / " + Format(snapshot.IoWriteMegabytes) + " MB") : "—"); string detail = (snapshot.ProcessIoAvailable ? (ProfilerTranslations.Text("read_write_rate") + ": " + Format(snapshot.IoReadRateAverageMegabytesPerSecond) + " / " + Format(snapshot.IoWriteRateAverageMegabytesPerSecond)) : "—"); Card(stringBuilder, ProfilerTranslations.Text("storage_io"), value2, detail); bool flag = snapshot.RemoteServerMetricSamples > 0; bool flag2 = snapshot.IsServerRuntime && snapshot.FixedUpdatesPerSecondAverage > 0.0; string value3 = (flag ? (Format(snapshot.RemoteServerTicksAverage) + " / " + Format(snapshot.RemoteServerTicksMinimum) + " / " + Format(snapshot.RemoteServerTicksMaximum)) : (flag2 ? (Format(snapshot.FixedUpdatesPerSecondAverage) + " / " + Format(snapshot.FixedUpdatesPerSecondMinimum) + " / " + Format(snapshot.FixedUpdatesPerSecondMaximum)) : "—")); string detail2 = (flag ? ProfilerTranslations.Format("server_detail", Format(snapshot.RemoteServerTargetTicks), Format(snapshot.RemoteServerCpuAverage), FormatMemory(snapshot.RemoteServerRamAverageMegabytes)) : (flag2 ? ProfilerTranslations.Format("server_detail", Format(snapshot.TargetFixedUpdatesPerSecond), Format(snapshot.CpuPercentAverage), FormatMemory(snapshot.ProcessRamAverageMegabytes)) : ProfilerTranslations.Text("server_missing"))); Card(stringBuilder, ProfilerTranslations.Text("server_ticks"), value3, detail2); Card(stringBuilder, "Valheim", Html(snapshot.RuntimeVersion)); Card(stringBuilder, ProfilerTranslations.Text("hide_valheim_callbacks"), ProfilerTranslations.Text(ProfilerDataView.HideVanilla ? "yes" : "no")); int num = 0; for (int i = 0; i < visibleObjects.Count; i++) { num += visibleObjects[i].CurrentInstances; } Card(stringBuilder, ProfilerTranslations.Text("tab_visible_objects"), snapshot.VisibleObjectScanAvailable ? num.ToString("N0", numberCulture) : "—", snapshot.VisibleObjectScanAvailable ? (ProfilerTranslations.Text("tab_visible_objects") + ": " + num.ToString("N0", numberCulture)) : ProfilerTranslations.Text("object_scan_policy")); stringBuilder.AppendLine("</div>"); stringBuilder.Append("<h2>").Append(Html(ProfilerTranslations.Text("mod_cost_heading"))).AppendLine("</h2>"); stringBuilder.Append("<p class=\"hint\">").Append(Html(ProfilerTranslations.Text("mods_help"))).AppendLine("</p>"); stringBuilder.AppendLine("<div class=\"table-wrap\"><table class=\"interactive\"><thead><tr>"); Header(stringBuilder, ProfilerTranslations.Text("mod_or_game")); Header(stringBuilder, ProfilerTranslations.Text("calls"), numeric: true); Header(stringBuilder, ProfilerTranslations.Text("self_ms"), numeric: true); Header(stringBuilder, ProfilerTranslations.Text("budget"), numeric: true); Header(stringBuilder, ProfilerTranslations.Text("measured_share_short"), numeric: true); stringBuilder.AppendLine("</tr></thead><tbody>"); for (int j = 0; j < groups.Count; j++) { AssemblyGroupMetric assemblyGroupMetric = groups[j]; string value4 = (assemblyGroupMetric.IsVanilla ? ProfilerTranslations.Text("vanilla_game") : assemblyGroupMetric.AssemblyName); double num2 = assemblyGroupMetric.FrameBudgetPercent(snapshot); double value5 = ((totalSelfMilliseconds <= 0.0) ? 0.0 : (assemblyGroupMetric.SelfMilliseconds * 100.0 / totalSelfMilliseconds)); stringBuilder.AppendLine("<tr>"); stringBuilder.Append("<td data-sort=\"").Append(Html(value4)).Append("\"><details><summary>") .Append(Html(value4)) .AppendLine("</summary><div class=\"nested\">"); AppendCallbackTable(stringBuilder, assemblyGroupMetric, snapshot); stringBuilder.AppendLine("</div></details></td>"); Cell(stringBuilder, assemblyGroupMetric.Calls.ToString("N0", numberCulture), assemblyGroupMetric.Calls.ToString(CultureInfo.InvariantCulture), "number"); Cell(stringBuilder, Format(assemblyGroupMetric.SelfMilliseconds), assemblyGroupMetric.SelfMilliseconds.ToString("0.000000", CultureInfo.InvariantCulture), "number"); Cell(stringBuilder, Format(num2) + "%", num2.ToString("0.000000", CultureInfo.InvariantCulture), "number " + ImpactClass(num2