Decompiled source of Instant Collapses v1.0.3

plugins\FasterCollapsesMod.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using PettersDevTools;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("FasterCollapsesMod")]
[assembly: AssemblyDescription("Valheim faster collapses")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FasterCollapsesMod")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3b4c5d6-a7f8-1029-bcda-fe4567890123")]
[assembly: AssemblyFileVersion("1.0.3")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
namespace FasterCollapsesMod
{
	[BepInPlugin("se.petterhansson.fastercollapsesmod", "FasterCollapsesMod", "1.0.3")]
	internal class FasterCollapsesMod : BaseUnityPlugin
	{
		public const string PluginGUID = "se.petterhansson.fastercollapsesmod";

		public const string PluginName = "FasterCollapsesMod";

		public const string PluginVersion = "1.0.3";

		private Harmony _harmony;

		public void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin se.petterhansson.fastercollapsesmod is loaded!");
			((Component)this).gameObject.AddComponent<StructuralGraph>();
			_harmony = new Harmony("se.petterhansson.fastercollapsesmod");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patching methods...");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patches applied successfully");
		}

		public void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public class StructuralGraph : MonoBehaviour
	{
		private readonly Dictionary<WearNTear, HashSet<WearNTear>> _adjacency = new Dictionary<WearNTear, HashSet<WearNTear>>();

		private readonly HashSet<WearNTear> _groundedPieces = new HashSet<WearNTear>();

		private readonly HashSet<WearNTear> _fullyRegistered = new HashSet<WearNTear>();

		private int _terrainLayer;

		private int _rayMask;

		private Collider[] _tempColliders = (Collider[])(object)new Collider[128];

		public static StructuralGraph Instance { get; private set; }

		public void Awake()
		{
			Instance = this;
			_terrainLayer = LayerMask.NameToLayer("terrain");
			_rayMask = LayerMask.GetMask(new string[5] { "piece", "Default", "static_solid", "Default_small", "terrain" });
			RebuildGraph();
		}

		public void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		public void RebuildGraph()
		{
			_adjacency.Clear();
			_groundedPieces.Clear();
			_fullyRegistered.Clear();
			List<WearNTear> allInstances = WearNTear.GetAllInstances();
			if (allInstances == null)
			{
				return;
			}
			foreach (WearNTear item in allInstances)
			{
				if ((Object)(object)item != (Object)null && ((Component)item).gameObject.activeInHierarchy)
				{
					Register(item);
				}
			}
		}

		public void RegisterDelayed(WearNTear wnt)
		{
			if (((Component)this).gameObject.activeInHierarchy)
			{
				((MonoBehaviour)this).StartCoroutine(RegisterCoroutine(wnt));
			}
		}

		private IEnumerator RegisterCoroutine(WearNTear wnt)
		{
			yield return null;
			Register(wnt);
		}

		public void Register(WearNTear wnt)
		{
			if ((Object)(object)wnt == (Object)null || _fullyRegistered.Contains(wnt))
			{
				return;
			}
			_fullyRegistered.Add(wnt);
			if (!_adjacency.ContainsKey(wnt))
			{
				_adjacency[wnt] = new HashSet<WearNTear>();
			}
			bool isGrounded = false;
			Collider[] componentsInChildren = ((Component)wnt).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!val.isTrigger && !((Object)(object)val.attachedRigidbody != (Object)null))
				{
					FindGroundedNeighborsGivenPieceCollider(wnt, val, ref isGrounded);
				}
			}
			if (isGrounded)
			{
				_groundedPieces.Add(wnt);
			}
		}

		private (Vector3 pos, Quaternion rot, Vector3 size) GetColliderBounds(Collider col)
		{
			//IL_009e: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_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_001f: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			BoxCollider val = (BoxCollider)(object)((col is BoxCollider) ? col : null);
			if (val != null)
			{
				Quaternion rotation = ((Component)val).transform.rotation;
				Vector3 item = ((Component)val).transform.position + ((Component)val).transform.TransformVector(val.center);
				Vector3 item2 = default(Vector3);
				((Vector3)(ref item2))..ctor(((Component)val).transform.lossyScale.x * val.size.x, ((Component)val).transform.lossyScale.y * val.size.y, ((Component)val).transform.lossyScale.z * val.size.z);
				return (pos: item, rot: rotation, size: item2);
			}
			Bounds bounds = col.bounds;
			Vector3 center = ((Bounds)(ref bounds)).center;
			Quaternion identity = Quaternion.identity;
			bounds = col.bounds;
			return (pos: center, rot: identity, size: ((Bounds)(ref bounds)).size);
		}

		private Vector3 GetInflatedBoundsForGroundingCheck(Vector3 size)
		{
			//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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			size.x += 0.3f;
			size.y += 0.3f;
			size.z += 0.3f;
			size *= 0.5f;
			return size;
		}

		private void FindGroundedNeighborsGivenPieceCollider(WearNTear wnt, Collider collider, ref bool isGrounded)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			(Vector3 pos, Quaternion rot, Vector3 size) colliderBounds = GetColliderBounds(collider);
			Vector3 item = colliderBounds.pos;
			Quaternion item2 = colliderBounds.rot;
			Vector3 item3 = colliderBounds.size;
			item3 = GetInflatedBoundsForGroundingCheck(item3);
			int num = Physics.OverlapBoxNonAlloc(item, item3, _tempColliders, item2, _rayMask);
			for (int i = 0; i < num; i++)
			{
				Collider val = _tempColliders[i];
				if ((Object)(object)val.attachedRigidbody != (Object)null || val.isTrigger || ((Component)val).transform.IsChildOf(((Component)wnt).transform))
				{
					continue;
				}
				if (((Component)val).gameObject.layer == _terrainLayer)
				{
					isGrounded = true;
					continue;
				}
				WearNTear componentInParent = ((Component)val).GetComponentInParent<WearNTear>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					isGrounded = true;
				}
				else if (componentInParent.m_supports)
				{
					AddAdjacency(wnt, componentInParent);
				}
			}
		}

		private void AddAdjacency(WearNTear wnt, WearNTear neighborWnt)
		{
			_adjacency[wnt].Add(neighborWnt);
			if (!_adjacency.TryGetValue(neighborWnt, out var value))
			{
				value = new HashSet<WearNTear>();
				_adjacency[neighborWnt] = value;
			}
			value.Add(wnt);
		}

		public void Unregister(WearNTear wnt)
		{
			if ((Object)(object)wnt == (Object)null)
			{
				return;
			}
			_fullyRegistered.Remove(wnt);
			if (!_adjacency.TryGetValue(wnt, out var value))
			{
				return;
			}
			foreach (WearNTear item in value)
			{
				if (_adjacency.TryGetValue(item, out var value2))
				{
					value2.Remove(wnt);
				}
			}
			_adjacency.Remove(wnt);
			_groundedPieces.Remove(wnt);
		}

		private static bool IsPositionNearUnloadedZone(Vector3 pos)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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)
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			Vector2s zone = ZoneSystem.GetZone(pos);
			Vector2s testZone = default(Vector2s);
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					if (i != 0 || j != 0)
					{
						((Vector2s)(ref testZone))..ctor(zone.x + i, zone.y + j);
						if (!ZoneSystem.instance.IsZoneLoaded(testZone) && IsPositionInExpandedZone(ref pos, ref testZone))
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private static bool IsPositionInExpandedZone(ref Vector3 pos, ref Vector2s testZone)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 zonePos = ZoneSystem.GetZonePos(testZone);
			if (pos.x >= zonePos.x - 42f && pos.x <= zonePos.x + 42f && pos.z >= zonePos.z - 42f)
			{
				return pos.z <= zonePos.z + 42f;
			}
			return false;
		}

		public void OnPieceDestroyed(WearNTear destroyedPiece)
		{
			List<WearNTear> list = new List<WearNTear>();
			if ((Object)(object)destroyedPiece == (Object)null || !_adjacency.TryGetValue(destroyedPiece, out var value))
			{
				return;
			}
			List<WearNTear> list2 = new List<WearNTear>(value);
			Unregister(destroyedPiece);
			HashSet<WearNTear> hashSet = new HashSet<WearNTear>();
			Queue<WearNTear> queue = new Queue<WearNTear>();
			foreach (WearNTear item in list2)
			{
				if (!hashSet.Contains(item))
				{
					bool foundGround;
					HashSet<WearNTear> collection = VisitConnectedComponent(item, out foundGround, queue, hashSet);
					if (!foundGround)
					{
						list.AddRange(collection);
					}
				}
			}
			if (list.Count == 0)
			{
				return;
			}
			foreach (WearNTear item2 in list)
			{
				if (!((Object)(object)item2 == (Object)null))
				{
					Unregister(item2);
					ZNetView component = ((Component)item2).GetComponent<ZNetView>();
					if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner())
					{
						item2.Remove(false);
					}
				}
			}
		}

		private HashSet<WearNTear> VisitConnectedComponent(WearNTear start, out bool foundGround, Queue<WearNTear> queue, HashSet<WearNTear> visitedGlobal)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			HashSet<WearNTear> hashSet = new HashSet<WearNTear>();
			foundGround = false;
			queue.Clear();
			queue.Enqueue(start);
			hashSet.Add(start);
			visitedGlobal.Add(start);
			while (queue.Count > 0)
			{
				WearNTear val = queue.Dequeue();
				if (_groundedPieces.Contains(val))
				{
					foundGround = true;
					break;
				}
				if (IsPositionNearUnloadedZone(((Component)val).transform.position))
				{
					foundGround = true;
					break;
				}
				if (!_adjacency.TryGetValue(val, out var value))
				{
					continue;
				}
				foreach (WearNTear item in value)
				{
					if (!visitedGlobal.Contains(item))
					{
						visitedGlobal.Add(item);
						hashSet.Add(item);
						queue.Enqueue(item);
					}
				}
			}
			return hashSet;
		}

		[Conditional("DEBUG")]
		private void DebugMarkDestruction(IEnumerable<WearNTear> pieces)
		{
		}
	}
	internal static class ModVersion
	{
		public const string Version = "1.0.3";
	}
}
namespace FasterCollapsesMod.Patches
{
	[HarmonyPatch(typeof(WearNTear))]
	public static class StructuralGraphPatches
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		public static void Awake_Postfix(WearNTear __instance)
		{
			using (new TimingScope(typeof(StructuralGraphPatches), "Awake_Postfix"))
			{
				if ((Object)(object)StructuralGraph.Instance != (Object)null)
				{
					StructuralGraph.Instance.RegisterDelayed(__instance);
				}
			}
		}

		[HarmonyPatch("Destroy")]
		[HarmonyPrefix]
		public static void Destroy_Prefix(WearNTear __instance)
		{
			using (new TimingScope(typeof(StructuralGraphPatches), "Destroy_Prefix"))
			{
				if ((Object)(object)StructuralGraph.Instance != (Object)null)
				{
					StructuralGraph.Instance.OnPieceDestroyed(__instance);
				}
			}
		}

		[HarmonyPatch("OnDestroy")]
		[HarmonyPrefix]
		public static void OnDestroy_Prefix(WearNTear __instance)
		{
			using (new TimingScope(typeof(StructuralGraphPatches), "OnDestroy_Prefix"))
			{
				if ((Object)(object)StructuralGraph.Instance != (Object)null)
				{
					StructuralGraph.Instance.Unregister(__instance);
				}
			}
		}
	}
}
namespace PettersDevTools
{
	internal class DebugLine
	{
		private static Dictionary<string, DebugLine> s_activeLines = new Dictionary<string, DebugLine>();

		private LineRenderer m_line;

		private Transform m_hostTransform;

		private Transform m_targetTransform;

		private Vector3 m_targetPosition;

		private bool m_useTransformTarget;

		private Vector3 m_startOffset = Vector3.up;

		private Vector3 m_endOffset = Vector3.up;

		public Transform TargetTransform => m_targetTransform;

		private DebugLine(LineRenderer line, Transform host)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			m_line = line;
			m_hostTransform = host;
		}

		public static DebugLine GetOrCreate(GameObject host, string name, Color color)
		{
			return null;
		}

		public void SetTarget(Transform target, Vector3 startOffset, Vector3 endOffset)
		{
		}

		public void SetTarget(Vector3 staticTarget, Vector3 startOffset, Vector3 endOffset)
		{
		}

		public void Hide()
		{
		}

		public void UpdateLine()
		{
		}

		public static void UpdateAllFor(GameObject host)
		{
		}

		public static void ClearAllFor(GameObject host)
		{
		}
	}
	internal static class Log
	{
		public static ManualLogSource Handle { get; set; }

		public static void Info(params object[] args)
		{
			if (Handle == null)
			{
				Debug.LogError((object)"[PettersDevTools] Cannot log because Log.Handle is null!");
			}
			else
			{
				Handle.LogInfo((object)string.Join(" ", args));
			}
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
	internal static class DebugLineUpdaterPatch
	{
		public static void Postfix(MonsterAI __instance)
		{
		}
	}
	internal static class StatsManager
	{
		private static readonly Dictionary<string, object> _stats = new Dictionary<string, object>();

		[Conditional("DEBUG")]
		public static void SetStat(string key, object value)
		{
			_stats[key] = value;
		}

		[Conditional("DEBUG")]
		public static void IncrementStat(string key, int amount = 1)
		{
			if (_stats.TryGetValue(key, out var value) && value is int num)
			{
				_stats[key] = num + amount;
			}
			else
			{
				_stats[key] = amount;
			}
		}

		public static void Clear()
		{
			_stats.Clear();
		}

		public static IEnumerable<KeyValuePair<string, object>> GetStats()
		{
			return _stats;
		}
	}
	internal interface ITimingRegistry
	{
		void SubmitTime(Type theclass, string method, long stopwatchTicks);

		void Clear();
	}
	internal class TimingManager : MonoBehaviour, ITimingRegistry
	{
		private struct TimingInfo
		{
			public long TotalTicks;

			public long LongestCall;

			public int Calls;

			public long AverageCall => TotalTicks / Mathf.Max(1, Calls);
		}

		private enum WindowState
		{
			Closed,
			Profiler,
			Stats
		}

		private static readonly double _conversionFactor = 1.0 / (double)Stopwatch.Frequency;

		private Dictionary<(Type, string), TimingInfo> _timings;

		private List<((Type, string), TimingInfo)> _worklist;

		private WindowState _windowState;

		public static ITimingRegistry Instance { get; private set; }

		private void Awake()
		{
			_timings = new Dictionary<(Type, string), TimingInfo>();
			_worklist = new List<((Type, string), TimingInfo)>();
			_windowState = WindowState.Closed;
			Instance = this;
		}

		private static double GetTime(long ticks)
		{
			return _conversionFactor * (double)ticks;
		}

		public void Clear()
		{
			_timings?.Clear();
		}

		public void SubmitTime(Type theclass, string method, long stopwatchTicks)
		{
			(Type, string) key = (theclass, method);
			if (!_timings.TryGetValue(key, out var value))
			{
				value = default(TimingInfo);
			}
			value.TotalTicks += stopwatchTicks;
			value.LongestCall = Math.Max(value.LongestCall, stopwatchTicks);
			value.Calls++;
			_timings[key] = value;
		}

		private IEnumerable<string> GetTopCallStrings(int maxCount = 10)
		{
			List<((Type, string), TimingInfo)> worklist = _worklist;
			worklist.Clear();
			foreach (KeyValuePair<(Type, string), TimingInfo> timing in _timings)
			{
				worklist.Add((timing.Key, timing.Value));
			}
			worklist.Sort((((Type, string), TimingInfo) a, ((Type, string), TimingInfo) b) => b.Item2.LongestCall.CompareTo(a.Item2.LongestCall));
			int count = 0;
			foreach (var item5 in worklist)
			{
				(Type, string) item = item5.Item1;
				Type item2 = item.Item1;
				string item3 = item.Item2;
				TimingInfo item4 = item5.Item2;
				yield return item2.Name + "." + item3 + ": " + (1000.0 * GetTime(item4.LongestCall)).ToString("F1") + " ms";
				int num = count + 1;
				count = num;
				if (num >= maxCount)
				{
					break;
				}
			}
		}

		private void CopyToClipboard()
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (_windowState == WindowState.Profiler)
			{
				stringBuilder.AppendLine("Longest calls:");
				foreach (string topCallString in GetTopCallStrings())
				{
					stringBuilder.AppendLine(topCallString);
				}
			}
			else if (_windowState == WindowState.Stats)
			{
				stringBuilder.AppendLine("Stats:");
				List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>(StatsManager.GetStats());
				list.Sort((KeyValuePair<string, object> a, KeyValuePair<string, object> b) => string.Compare(a.Key, b.Key, StringComparison.OrdinalIgnoreCase));
				foreach (KeyValuePair<string, object> item in list)
				{
					stringBuilder.AppendLine($"{item.Key}: {item.Value}");
				}
			}
			GUIUtility.systemCopyBuffer = stringBuilder.ToString();
		}

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)290) && !Console.IsVisible())
			{
				_windowState = (WindowState)((int)(_windowState + 1) % 3);
			}
			if (Input.GetKeyDown((KeyCode)291) && !Console.IsVisible())
			{
				CopyToClipboard();
			}
			if (Input.GetKeyDown((KeyCode)293) && !Console.IsVisible())
			{
				Clear();
				StatsManager.Clear();
			}
		}

		private void OnGUI()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (_windowState == WindowState.Closed)
			{
				return;
			}
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(200f, 200f, 500f, 400f);
			GUILayout.BeginArea(val);
			if ((int)Event.current.type == 8 || (int)Event.current.type == 7)
			{
				GUILayout.Button("", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.ExpandWidth(true),
					GUILayout.ExpandHeight(true)
				});
			}
			GUILayout.EndArea();
			GUILayout.BeginArea(val);
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			if (_windowState == WindowState.Profiler)
			{
				GUILayout.Label("Longest calls:", Array.Empty<GUILayoutOption>());
				foreach (string topCallString in GetTopCallStrings())
				{
					GUILayout.Label(topCallString, Array.Empty<GUILayoutOption>());
				}
			}
			else if (_windowState == WindowState.Stats)
			{
				GUILayout.Label("Stats:", Array.Empty<GUILayoutOption>());
				List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>(StatsManager.GetStats());
				list.Sort((KeyValuePair<string, object> a, KeyValuePair<string, object> b) => string.Compare(a.Key, b.Key, StringComparison.OrdinalIgnoreCase));
				foreach (KeyValuePair<string, object> item in list)
				{
					GUILayout.Label($"{item.Key}: {item.Value}", Array.Empty<GUILayoutOption>());
				}
			}
			GUILayout.FlexibleSpace();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Next (F9)", Array.Empty<GUILayoutOption>()))
			{
				_windowState = (WindowState)((int)(_windowState + 1) % 3);
			}
			if (GUILayout.Button("Copy (F10)", Array.Empty<GUILayoutOption>()))
			{
				CopyToClipboard();
			}
			if (GUILayout.Button("Reset (F12)", Array.Empty<GUILayoutOption>()))
			{
				Clear();
				StatsManager.Clear();
			}
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
			GUILayout.EndArea();
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct TimingScope : IDisposable
	{
		public TimingScope(Type theclass, string method)
		{
		}

		public void Dispose()
		{
		}
	}
}