Decompiled source of DragUI v1.2.0

DragUI.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using DragUI.Data;
using DragUI.Patches;
using DragUI.Services;
using DragUI.UI;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using ProjectM;
using ProjectM.Network;
using ProjectM.Physics;
using ProjectM.Scripting;
using ProjectM.Shared;
using ProjectM.UI;
using Stunlock.Core;
using TMPro;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DragUI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Client-side utility UI for V Rising: V Blood hunt tracker, familiar quick-summon, one-click loadouts, DPS meter, XP/hour, full character sheet, teleport tools and boss alarms.")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+baae0b0083883316a0c0b2c1477218f6c37fa158")]
[assembly: AssemblyProduct("DragUI")]
[assembly: AssemblyTitle("DragUI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 DragUI
{
	internal static class Core
	{
		private static World _client;

		private static ClientScriptMapper _clientScriptMapper;

		private static Entity _localCharacter = Entity.Null;

		private static Entity _localUser = Entity.Null;

		private static bool _warnedBadServerTime;

		public static ManualLogSource Log => Plugin.LogInstance;

		public static bool IsReady
		{
			get
			{
				if (_client != null)
				{
					return _client.IsCreated;
				}
				return false;
			}
		}

		public static World Client => _client;

		public static EntityManager EntityManager => _client.EntityManager;

		public static ClientScriptMapper ClientScriptMapper => _clientScriptMapper ?? (_clientScriptMapper = _client.GetExistingSystemManaged<ClientScriptMapper>());

		public static Entity LocalCharacter
		{
			get
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: 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_002a: 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)
				if (IsReady)
				{
					if (!_localCharacter.Exists())
					{
						if (!ConsoleShared.TryGetLocalCharacterInCurrentWorld(ref _localCharacter, _client))
						{
							return Entity.Null;
						}
						return _localCharacter;
					}
					return _localCharacter;
				}
				return Entity.Null;
			}
		}

		public static Entity LocalUser
		{
			get
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: 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_002a: 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)
				if (IsReady)
				{
					if (!_localUser.Exists())
					{
						if (!ConsoleShared.TryGetLocalUserInCurrentWorld(ref _localUser, _client))
						{
							return Entity.Null;
						}
						return _localUser;
					}
					return _localUser;
				}
				return Entity.Null;
			}
		}

		public static bool InGame
		{
			get
			{
				//IL_0007: 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)
				if (IsReady)
				{
					return LocalCharacter != Entity.Null;
				}
				return false;
			}
		}

		public static bool TryGetServerTime(out double serverTime)
		{
			//IL_0011: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			serverTime = 0.0;
			try
			{
				serverTime = ClientScriptMapper._ClientGameManager.ServerTime.Time;
			}
			catch (Exception ex)
			{
				if (!_warnedBadServerTime)
				{
					ManualLogSource log = Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(27, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Couldn't read server time: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
				_warnedBadServerTime = true;
				return false;
			}
			if (double.IsFinite(serverTime) && serverTime > 0.0)
			{
				return true;
			}
			if (!_warnedBadServerTime)
			{
				ManualLogSource log2 = Log;
				bool flag2 = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(56, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Server time not usable yet (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(serverTime);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); exact timers wait for it.");
				}
				log2.LogWarning(val);
			}
			_warnedBadServerTime = true;
			return false;
		}

		public static bool TryServerToLocal(double serverTimestamp, out double local)
		{
			local = 0.0;
			if (!double.IsFinite(serverTimestamp) || serverTimestamp <= 0.0 || !TryGetServerTime(out var serverTime))
			{
				return false;
			}
			local = VBloodTracker.Now + (serverTimestamp - serverTime);
			return double.IsFinite(local);
		}

		public static bool IsBoundTo(World world)
		{
			if (_client != null && world != null)
			{
				return ((Il2CppObjectBase)_client).Pointer == ((Il2CppObjectBase)world).Pointer;
			}
			return false;
		}

		public static void Initialize(World world)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if (!IsBoundTo(world))
			{
				Reset();
				_client = world;
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(22, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Client world bound (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(world.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
				}
				log.LogInfo(val);
			}
		}

		public static void Reset()
		{
			//IL_0012: 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_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)
			_client = null;
			_clientScriptMapper = null;
			_warnedBadServerTime = false;
			_localCharacter = Entity.Null;
			_localUser = Entity.Null;
		}

		public static bool TryGetLocalPosition(out float2 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0024: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0034: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			position = default(float2);
			Entity localCharacter = LocalCharacter;
			if (localCharacter == Entity.Null || !localCharacter.Has<LocalToWorld>())
			{
				return false;
			}
			LocalToWorld val = localCharacter.Read<LocalToWorld>();
			float3 position2 = ((LocalToWorld)(ref val)).Position;
			position = new float2(position2.x, position2.z);
			return true;
		}

		public static EntityQuery BuildQuery(params Type[] all)
		{
			//IL_0003: 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_001f: 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_0034: 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)
			EntityQueryBuilder val = default(EntityQueryBuilder);
			((EntityQueryBuilder)(ref val))..ctor(AllocatorHandle.op_Implicit((Allocator)2));
			foreach (Type val2 in all)
			{
				((EntityQueryBuilder)(ref val)).AddAll(ComponentType.ReadOnly(val2));
			}
			EntityManager entityManager = EntityManager;
			EntityQuery result = ((EntityManager)(ref entityManager)).CreateEntityQuery(ref val);
			((EntityQueryBuilder)(ref val)).Dispose();
			return result;
		}

		public static void Diag(string message)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			if (Settings.Diagnostics)
			{
				ManualLogSource log = Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(7, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[diag] ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(message);
				}
				log.LogInfo(val);
			}
		}
	}
	internal static class EntityExtensions
	{
		private static EntityManager EM => Core.EntityManager;

		public static bool Exists(this Entity entity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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_0019: 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)
			if (entity != Entity.Null && Core.IsReady)
			{
				EntityManager eM = EM;
				return ((EntityManager)(ref eM)).Exists(entity);
			}
			return false;
		}

		public static bool Has<T>(this Entity entity)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			EntityManager eM = EM;
			return ((EntityManager)(ref eM)).HasComponent<T>(entity);
		}

		public static T Read<T>(this Entity entity) where T : struct
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			EntityManager eM = EM;
			T result = default(T);
			if (!((EntityManager)(ref eM)).TryGetComponentData<T>(entity, ref result))
			{
				return default(T);
			}
			return result;
		}

		public static void Write<T>(this Entity entity, T data) where T : struct
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			EntityManager eM = EM;
			((EntityManager)(ref eM)).SetComponentData<T>(entity, data);
		}
	}
	[BepInPlugin("nezoic.DragUI", "DragUI", "1.2.0")]
	internal class Plugin : BasePlugin
	{
		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource LogInstance => ((BasePlugin)Instance).Log;

		internal static string DataDirectory => Path.Combine(Paths.ConfigPath, "DragUI");

		public override void Load()
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			Instance = this;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val;
			if (Application.productName == "VRisingServer")
			{
				ManualLogSource log = ((BasePlugin)this).Log;
				val = new BepInExInfoLogInterpolatedStringHandler(44, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("DragUI");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" is a client mod; not loading on the server.");
				}
				log.LogInfo(val);
				return;
			}
			MigrateFromVBloodHunter();
			Settings.Initialize(((BasePlugin)this).Config);
			HuntStore.Load();
			RespawnMemory.Load();
			FamiliarStore.Load();
			BossAlarm.Load();
			_harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "nezoic.DragUI");
			Ticker.Start();
			ManualLogSource log2 = ((BasePlugin)this).Log;
			val = new BepInExInfoLogInterpolatedStringHandler(40, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("DragUI");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.2.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] loaded; waiting for the client world.");
			}
			log2.LogInfo(val);
		}

		private void MigrateFromVBloodHunter()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			try
			{
				string text = Path.Combine(Paths.ConfigPath, "nezoic.VBloodHunter.cfg");
				if (File.Exists(text) && !File.Exists(((BasePlugin)this).Config.ConfigFilePath))
				{
					File.Copy(text, ((BasePlugin)this).Config.ConfigFilePath);
					((BasePlugin)this).Config.Reload();
					((BasePlugin)this).Log.LogInfo((object)"Settings carried over from VBloodHunter.");
				}
				string text2 = Path.Combine(Paths.ConfigPath, "VBloodHunter");
				if (Directory.Exists(text2) && !Directory.Exists(DataDirectory))
				{
					Directory.Move(text2, DataDirectory);
					((BasePlugin)this).Log.LogInfo((object)"Data folder carried over from VBloodHunter.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = ((BasePlugin)this).Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(50, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Couldn't carry over VBloodHunter's settings/data: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val);
			}
		}

		public override bool Unload()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			Ticker.Stop();
			AlarmSound.Stop();
			UIManager.Destroy();
			Core.Reset();
			return true;
		}
	}
	internal static class Settings
	{
		private static ConfigEntry<KeyCode> _toggleKey;

		private static ConfigEntry<float> _uiScale;

		private static ConfigEntry<float> _pollSeconds;

		private static ConfigEntry<int> _fallbackRespawnSeconds;

		private static ConfigEntry<bool> _learnRespawnTimes;

		private static ConfigEntry<bool> _autoTrackNext;

		private static ConfigEntry<bool> _readChatKills;

		private static ConfigEntry<string> _chatKillChannels;

		private static ConfigEntry<string> _chatKillWords;

		private static ConfigEntry<bool> _blockClicksOverUI;

		private static ConfigEntry<bool> _diagnostics;

		private static ConfigEntry<float> _hudX;

		private static ConfigEntry<float> _hudY;

		private static ConfigEntry<float> _panelX;

		private static ConfigEntry<float> _panelY;

		private static ConfigEntry<float> _barX;

		private static ConfigEntry<float> _barY;

		private static ConfigEntry<float> _famPanelX;

		private static ConfigEntry<float> _famPanelY;

		private static ConfigEntry<bool> _hudCollapsed;

		private static ConfigEntry<bool> _hudVisible;

		private static ConfigEntry<float> _barWidth;

		private static ConfigEntry<bool> _familiarsEnabled;

		private static ConfigEntry<bool> _lockKeysWhileTyping;

		private static ConfigEntry<bool> _alarmEnabled;

		private static ConfigEntry<bool> _autoTeleport;

		private static ConfigEntry<string> _autoTeleportOnlyFrom;

		private static ConfigEntry<bool> _xpEnabled;

		private static ConfigEntry<bool> _dpsEnabled;

		private static ConfigEntry<bool> _sheetEnabled;

		private static ConfigEntry<bool> _cooldownTesterEnabled;

		private static ConfigEntry<bool> _loadoutsEnabled;

		private static ConfigEntry<float> _loadoutPanelX;

		private static ConfigEntry<float> _loadoutPanelY;

		private static ConfigEntry<bool> _statChoicesEnabled;

		private static ConfigEntry<float> _weaponStatsPanelX;

		private static ConfigEntry<float> _weaponStatsPanelY;

		private static ConfigEntry<float> _bloodStatsPanelX;

		private static ConfigEntry<float> _bloodStatsPanelY;

		private static ConfigEntry<float> _noctveilPanelX;

		private static ConfigEntry<float> _noctveilPanelY;

		private static ConfigEntry<float> _teleportPanelX;

		private static ConfigEntry<float> _teleportPanelY;

		private static ConfigEntry<float> _teleportPopoutX;

		private static ConfigEntry<float> _teleportPopoutY;

		private static ConfigEntry<bool> _teleportPopoutVisible;

		private static ConfigEntry<float> _cdPanelX;

		private static ConfigEntry<float> _cdPanelY;

		private static ConfigEntry<float> _sheetPanelX;

		private static ConfigEntry<float> _sheetPanelY;

		private static ConfigEntry<float> _dpsFightTimeout;

		private static ConfigEntry<float> _dpsPanelX;

		private static ConfigEntry<float> _dpsPanelY;

		private static ConfigEntry<bool> _hideXpMessages;

		private static ConfigEntry<float> _xpIdleMinutes;

		private static ConfigEntry<float> _xpPanelX;

		private static ConfigEntry<float> _xpPanelY;

		private static ConfigEntry<float> _alarmVolume;

		private static ConfigEntry<float> _alarmLeadMinutes;

		private static ConfigEntry<float> _alarmButtonMinutes;

		private static ConfigEntry<float> _alarmFlashMinutes;

		private static ConfigEntry<string> _alarmTimeZone;

		public static KeyCode ToggleKey => _toggleKey.Value;

		public static float UIScale => Mathf.Clamp(_uiScale.Value, 0.5f, 2.5f);

		public static float PollSeconds => Mathf.Max(2f, _pollSeconds.Value);

		public static int FallbackRespawnSeconds => Math.Max(30, _fallbackRespawnSeconds.Value);

		public static bool LearnRespawnTimes => _learnRespawnTimes.Value;

		public static bool AutoTrackNext => _autoTrackNext.Value;

		public static bool ReadChatKills => _readChatKills.Value;

		public static string ChatKillChannels => _chatKillChannels.Value ?? string.Empty;

		public static string ChatKillWords => _chatKillWords.Value ?? string.Empty;

		public static bool BlockClicksOverUI => _blockClicksOverUI.Value;

		public static bool Diagnostics => _diagnostics.Value;

		public static bool FamiliarsEnabled => _familiarsEnabled.Value;

		public static bool LockKeysWhileTyping => _lockKeysWhileTyping.Value;

		public static bool XpEnabled => _xpEnabled.Value;

		public static bool DpsEnabled => _dpsEnabled.Value;

		public static bool SheetEnabled => _sheetEnabled.Value;

		public static bool CooldownTesterEnabled => _cooldownTesterEnabled.Value;

		public static bool LoadoutsEnabled => _loadoutsEnabled.Value;

		public static bool StatChoicesEnabled => _statChoicesEnabled.Value;

		public static float DpsFightTimeoutSeconds => Mathf.Clamp(_dpsFightTimeout.Value, 2f, 60f);

		public static bool HideXpMessages => _hideXpMessages.Value;

		public static float XpIdleMinutes => Mathf.Max(1f, _xpIdleMinutes.Value);

		public static bool AutoTeleportEnabled
		{
			get
			{
				return _autoTeleport.Value;
			}
			set
			{
				_autoTeleport.Value = value;
			}
		}

		public static string AutoTeleportOnlyFrom => _autoTeleportOnlyFrom.Value ?? string.Empty;

		public static bool AlarmEnabled
		{
			get
			{
				return _alarmEnabled.Value;
			}
			set
			{
				_alarmEnabled.Value = value;
			}
		}

		public static float AlarmVolume => Mathf.Clamp01(_alarmVolume.Value);

		public static float AlarmLeadMinutes => Mathf.Clamp(_alarmLeadMinutes.Value, 0f, 60f);

		public static float AlarmButtonMinutes => Mathf.Max(0.5f, _alarmButtonMinutes.Value);

		public static float AlarmFlashMinutes => Mathf.Max(0f, _alarmFlashMinutes.Value);

		public static string AlarmTimeZone => _alarmTimeZone.Value ?? string.Empty;

		public static Vector2 HudPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_hudX.Value, _hudY.Value);
			}
			set
			{
				//IL_0005: 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)
				_hudX.Value = Mathf.Round(value.x);
				_hudY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 PanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_panelX.Value, _panelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_panelX.Value = Mathf.Round(value.x);
				_panelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 BarPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_barX.Value, _barY.Value);
			}
			set
			{
				//IL_0005: 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)
				_barX.Value = Mathf.Round(value.x);
				_barY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 FamiliarPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_famPanelX.Value, _famPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_famPanelX.Value = Mathf.Round(value.x);
				_famPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 CooldownPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_cdPanelX.Value, _cdPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_cdPanelX.Value = Mathf.Round(value.x);
				_cdPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 CharacterPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_sheetPanelX.Value, _sheetPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_sheetPanelX.Value = Mathf.Round(value.x);
				_sheetPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 LoadoutPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_loadoutPanelX.Value, _loadoutPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_loadoutPanelX.Value = Mathf.Round(value.x);
				_loadoutPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 WeaponStatsPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_weaponStatsPanelX.Value, _weaponStatsPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_weaponStatsPanelX.Value = Mathf.Round(value.x);
				_weaponStatsPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 BloodStatsPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_bloodStatsPanelX.Value, _bloodStatsPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_bloodStatsPanelX.Value = Mathf.Round(value.x);
				_bloodStatsPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 TeleportPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_teleportPanelX.Value, _teleportPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_teleportPanelX.Value = Mathf.Round(value.x);
				_teleportPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 TeleportPopoutPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_teleportPopoutX.Value, _teleportPopoutY.Value);
			}
			set
			{
				//IL_0005: 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)
				_teleportPopoutX.Value = Mathf.Round(value.x);
				_teleportPopoutY.Value = Mathf.Round(value.y);
			}
		}

		public static bool TeleportPopoutVisible
		{
			get
			{
				return _teleportPopoutVisible.Value;
			}
			set
			{
				_teleportPopoutVisible.Value = value;
			}
		}

		public static Vector2 NoctveilPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_noctveilPanelX.Value, _noctveilPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_noctveilPanelX.Value = Mathf.Round(value.x);
				_noctveilPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 DpsPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_dpsPanelX.Value, _dpsPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_dpsPanelX.Value = Mathf.Round(value.x);
				_dpsPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static Vector2 XpPanelPosition
		{
			get
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				return new Vector2(_xpPanelX.Value, _xpPanelY.Value);
			}
			set
			{
				//IL_0005: 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)
				_xpPanelX.Value = Mathf.Round(value.x);
				_xpPanelY.Value = Mathf.Round(value.y);
			}
		}

		public static bool HudCollapsed
		{
			get
			{
				return _hudCollapsed.Value;
			}
			set
			{
				_hudCollapsed.Value = value;
			}
		}

		public static bool HudVisible
		{
			get
			{
				return _hudVisible.Value;
			}
			set
			{
				_hudVisible.Value = value;
			}
		}

		public static float BarWidth
		{
			get
			{
				return Mathf.Max(0f, _barWidth.Value);
			}
			set
			{
				_barWidth.Value = Mathf.Round(Mathf.Max(0f, value));
			}
		}

		public static void Initialize(ConfigFile config)
		{
			_toggleKey = config.Bind<KeyCode>("General", "ToggleListKey", (KeyCode)0, "Optional hotkey that opens/closes the V Blood list (e.g. F8). None = use the on-screen button only. Avoid keys you type in chat.");
			_uiScale = config.Bind<float>("General", "UIScale", 1f, "Scale of the hunt tracker and V Blood list (0.5 - 2.5).");
			_pollSeconds = config.Bind<float>("Tracking", "PollSeconds", 5f, "How often (seconds, min 2) to ask the server which V Bloods are alive. This is the same request the game's V Blood menu makes.");
			_fallbackRespawnSeconds = config.Bind<int>("Tracking", "FallbackRespawnSeconds", 600, "Respawn estimate (seconds) for a V Blood with no known default and no observed respawn yet.");
			_learnRespawnTimes = config.Bind<bool>("Tracking", "LearnRespawnTimes", true, "Remember respawn durations measured in-game (from V Blood ghosts and observed respawns) and use them for future estimates.");
			_autoTrackNext = config.Bind<bool>("Tracking", "AutoTrackNext", false, "When nothing is tracked (e.g. your tracked V Blood just died), automatically track the nearest alive V Blood on your hunt list.");
			_readChatKills = config.Bind<bool>("Chat", "ReadChatKills", true, "Start a respawn countdown when a server chat message announces a V Blood kill (from kill-feed/announcement mods). A message counts when it names exactly one V Blood and contains a kill word.");
			_chatKillChannels = config.Bind<string>("Chat", "ChatKillChannels", "System", "Chat channels to read kill announcements from, comma-separated: System, Global, Region, Team, Local, Lore. Announcement mods use System; adding Global lets player chat like 'killed alpha' start timers too.");
			_chatKillWords = config.Bind<string>("Chat", "ExtraChatKillWords", "", "Extra words that mark a chat message as a kill announcement, on top of the built-in ones (killed, slain, defeated, beating, ...). Comma-separated, whole words, case-insensitive.");
			_blockClicksOverUI = config.Bind<bool>("General", "BlockClicksOverUI", true, "Stop clicks on this mod's buttons from also firing your primary attack / casts in the world.");
			_lockKeysWhileTyping = config.Bind<bool>("General", "LockKeysWhileTyping", true, "While you type in one of this mod's text boxes, stop the keys from also moving your character or firing abilities (uses the same input lock as the game's chat box). Turn off only if typing in the mod causes problems.");
			_familiarsEnabled = config.Bind<bool>("Familiars", "Enabled", true, "Show the Familiars window (quick summon for Bloodcraft familiars). It sends Bloodcraft's chat commands (.fam sb, .fam t) for you, so it only works on servers running Bloodcraft with familiars enabled. On other servers the commands would show up as local chat, so turn this off there.");
			_cooldownTesterEnabled = config.Bind<bool>("Character", "CooldownTester", true, "Show a CD Test button on the control bar: a window that times your skills' real cooldowns against their base, to see how cooldown stats really work.");
			_loadoutsEnabled = config.Bind<bool>("Character", "Loadouts", true, "Show Loadouts in the control bar's Character menu: save your build (equipped gear, spell passives, Bloodcraft class and shift spell) and put a saved one back on with one click. Bloodcraft parts need a Bloodcraft server.");
			_statChoicesEnabled = config.Bind<bool>("Character", "StatChoices", true, "Show Weapon Stats and Blood Stats in the control bar's Character menu: pick and reset your Bloodcraft expertise and legacy stats. They send Bloodcraft's chat commands (.wep, .bl) for you, so they only work on servers running Bloodcraft.");
			_sheetEnabled = config.Bind<bool>("Character", "Enabled", true, "Show a Stats button on the control bar that opens a full character sheet: every stat and its sources (gear, buffs, Bloodcraft bonuses).");
			_dpsEnabled = config.Bind<bool>("Dps", "Enabled", true, "Show a DPS meter on the control bar: damage you (and your minions/familiar) deal per fight, per ability, from the damage numbers the server sends.");
			_dpsFightTimeout = config.Bind<float>("Dps", "FightTimeoutSeconds", 6f, "A fight ends this many seconds (2 - 60) after your last hit; the next hit starts a new one.");
			_xpEnabled = config.Bind<bool>("Experience", "Enabled", true, "Show experience per hour on the control bar, with a breakdown (quests / mobs / V Bloods) per prestige. Reads Bloodcraft's leveling log, so it needs a Bloodcraft server and the log on ('.lvl log', or the button in the XP window).");
			_hideXpMessages = config.Bind<bool>("Experience", "HideXpMessages", true, "Hide Bloodcraft's '+123 experience (45%)' chat lines (the XP window counts them instead of them filling chat).");
			_xpIdleMinutes = config.Bind<float>("Experience", "IdleMinutes", 5f, "A gap longer than this (minutes) without any experience isn't counted as play time, so being AFK doesn't lower XP/hour.");
			_autoTeleport = config.Bind<bool>("AutoTeleport", "Enabled", false, "Automatically accept ScarletTeleports teleport requests (sends '.stp tpa <name>' when someone requests to teleport to you). Toggle it in the Teleport window (Teleport on the control bar); with it off, requests wait there and in the notification slot.");
			_autoTeleportOnlyFrom = config.Bind<string>("AutoTeleport", "OnlyFrom", "", "Only auto-accept requests from these players (comma-separated character names). Empty = anyone who requests.");
			_alarmEnabled = config.Bind<bool>("BossAlarm", "Enabled", false, "Sound an alarm and show a teleport button at each time in BepInEx/config/DragUI/boss-schedule.txt. Server-specific: the default schedule is the Noctveil server's Apex/Prime bosses. Toggle it in Server Settings -> Noctveil on the control bar.");
			_alarmVolume = config.Bind<float>("BossAlarm", "Volume", 0.35f, "Alarm chime volume, 0 - 1 (0 = silent). Played through Windows, so the game's volume sliders don't affect it.");
			_alarmLeadMinutes = config.Bind<float>("BossAlarm", "LeadMinutes", 2f, "How many minutes before each boss spawns the alarm sounds and its teleport button appears (time to get out of combat).");
			_alarmButtonMinutes = config.Bind<float>("BossAlarm", "ButtonMinutes", 15f, "How long (minutes) the teleport button stays on the control bar after the boss spawns.");
			_alarmFlashMinutes = config.Bind<float>("BossAlarm", "FlashMinutes", 2f, "How long (minutes) the teleport button flashes after the alarm sounds. With LeadMinutes 2 it flashes until the boss spawns.");
			_alarmTimeZone = config.Bind<string>("BossAlarm", "TimeZone", "", "Time zone the schedule's times are in, as a Windows time zone id (e.g. 'Eastern Standard Time', 'Central Standard Time'). Empty = this PC's time zone.");
			_diagnostics = config.Bind<bool>("Debug", "Diagnostics", false, "Log what the mod sees (position responses, ghosts, tracking buffs). Turn on when reporting a problem.");
			_hudX = config.Bind<float>("Layout", "HudX", 16f, "Hunt tracker left edge, in reference pixels from the left of the screen. Drag the tracker header to change.");
			_hudY = config.Bind<float>("Layout", "HudY", -220f, "Hunt tracker top edge, in reference pixels from the top of the screen (negative = down).");
			_panelX = config.Bind<float>("Layout", "PanelX", 0f, "V Blood list window offset from the screen centre (x). Drag its title bar to change.");
			_panelY = config.Bind<float>("Layout", "PanelY", 0f, "V Blood list window offset from the screen centre (y).");
			_hudCollapsed = config.Bind<bool>("Layout", "HudCollapsed", false, "Whether the hunt tracker rows are collapsed (only the header button shows).");
			_hudVisible = config.Bind<bool>("Layout", "HudVisible", true, "Whether the hunt tracker is shown. Toggle it with the Tracker button on the control bar.");
			_barX = config.Bind<float>("Layout", "BarX", 16f, "Control bar left edge, in reference pixels from the left of the screen. Drag its grip to change.");
			_barY = config.Bind<float>("Layout", "BarY", -176f, "Control bar top edge, in reference pixels from the top of the screen (negative = down).");
			_barWidth = config.Bind<float>("Layout", "BarWidth", 0f, "Width of the control bar's button area, in reference pixels: the buttons wrap into as many rows as they need. 0 = one row; anything narrower than the widest button = one column. Drag the strip on the bar's right edge to change, or click its grip to switch between one row and one column.");
			_cdPanelX = config.Bind<float>("Layout", "CooldownPanelX", 0f, "Cooldown tester window offset from the screen centre (x). Drag its title bar to change.");
			_cdPanelY = config.Bind<float>("Layout", "CooldownPanelY", -60f, "Cooldown tester window offset from the screen centre (y).");
			_sheetPanelX = config.Bind<float>("Layout", "CharacterPanelX", 300f, "Character sheet window offset from the screen centre (x). Drag its title bar to change.");
			_sheetPanelY = config.Bind<float>("Layout", "CharacterPanelY", 0f, "Character sheet window offset from the screen centre (y).");
			_loadoutPanelX = config.Bind<float>("Layout", "LoadoutPanelX", -300f, "Loadouts window offset from the screen centre (x). Drag its title bar to change.");
			_loadoutPanelY = config.Bind<float>("Layout", "LoadoutPanelY", 60f, "Loadouts window offset from the screen centre (y).");
			_weaponStatsPanelX = config.Bind<float>("Layout", "WeaponStatsPanelX", -280f, "Weapon Stats window offset from the screen centre (x). Drag its title bar to change.");
			_weaponStatsPanelY = config.Bind<float>("Layout", "WeaponStatsPanelY", 0f, "Weapon Stats window offset from the screen centre (y).");
			_bloodStatsPanelX = config.Bind<float>("Layout", "BloodStatsPanelX", 280f, "Blood Stats window offset from the screen centre (x). Drag its title bar to change.");
			_bloodStatsPanelY = config.Bind<float>("Layout", "BloodStatsPanelY", 0f, "Blood Stats window offset from the screen centre (y).");
			_teleportPanelX = config.Bind<float>("Layout", "TeleportPanelX", -340f, "Teleport window offset from the screen centre (x). Drag its title bar to change.");
			_teleportPanelY = config.Bind<float>("Layout", "TeleportPanelY", 0f, "Teleport window offset from the screen centre (y).");
			_teleportPopoutX = config.Bind<float>("Layout", "TeleportPopoutX", 16f, "Teleport pop-out left edge, in reference pixels from the left of the screen. Drag its header to change.");
			_teleportPopoutY = config.Bind<float>("Layout", "TeleportPopoutY", -420f, "Teleport pop-out top edge, in reference pixels from the top of the screen (negative = down).");
			_teleportPopoutVisible = config.Bind<bool>("Layout", "TeleportPopoutVisible", false, "Whether the teleport pop-out (quick teleport buttons) is open. Open it with Pop out in the Teleport window.");
			_noctveilPanelX = config.Bind<float>("Layout", "NoctveilPanelX", 320f, "Noctveil server settings window offset from the screen centre (x). Drag its title bar to change.");
			_noctveilPanelY = config.Bind<float>("Layout", "NoctveilPanelY", 40f, "Noctveil server settings window offset from the screen centre (y).");
			_dpsPanelX = config.Bind<float>("Layout", "DpsPanelX", -320f, "DPS meter window offset from the screen centre (x). Drag its title bar to change.");
			_dpsPanelY = config.Bind<float>("Layout", "DpsPanelY", 0f, "DPS meter window offset from the screen centre (y).");
			_xpPanelX = config.Bind<float>("Layout", "XpPanelX", 0f, "Experience window offset from the screen centre (x). Drag its title bar to change.");
			_xpPanelY = config.Bind<float>("Layout", "XpPanelY", 120f, "Experience window offset from the screen centre (y).");
			_famPanelX = config.Bind<float>("Layout", "FamiliarPanelX", 380f, "Familiars window offset from the screen centre (x). Drag its title bar to change.");
			_famPanelY = config.Bind<float>("Layout", "FamiliarPanelY", 0f, "Familiars window offset from the screen centre (y).");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "nezoic.DragUI";

		public const string PLUGIN_NAME = "DragUI";

		public const string PLUGIN_VERSION = "1.2.0";
	}
}
namespace DragUI.UI
{
	internal sealed class CharacterPanel : Window
	{
		private const float PanelWidth = 560f;

		private const float LineHeight = 20f;

		private const int PoolSize = 220;

		private const float SummaryHeight = 58f;

		private const float ListTop = 109f;

		private const float FooterHeight = 34f;

		private readonly TextMeshProUGUI _summary;

		private readonly UIFactory.ScrollRef _scroll;

		private readonly (TextMeshProUGUI Left, TextMeshProUGUI Right, TextMeshProUGUI Note)[] _pool = new(TextMeshProUGUI, TextMeshProUGUI, TextMeshProUGUI)[220];

		private double _nextBuildAt;

		public override Vector2 SavedPosition
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return Settings.CharacterPanelPosition;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Settings.CharacterPanelPosition = value;
			}
		}

		public CharacterPanel(Transform parent)
			: base("Character", parent, "Character", "every stat and where it comes from", 560f, 640f)
		{
			//IL_0046: 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_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			_summary = UIFactory.CreateText("Summary", (Transform)(object)base.Root, string.Empty, 12f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_summary).enableWordWrapping = true;
			((TMP_Text)_summary).rectTransform.Place(14f, 47f, Width - 150f, 52f);
			UIFactory.CreateButton("RefreshPerks", (Transform)(object)base.Root, "Refresh perks", 12f, delegate
			{
				PerkshopStats.Sync();
				_nextBuildAt = 0.0;
			}, 12f).Rect.Place(Width - 130f, 51f, 118f, 24f);
			UIFactory.CreateDivider((Transform)(object)base.Root, 12f, 105f, Width - 24f);
			_scroll = UIFactory.CreateScrollView("Stats", (Transform)(object)base.Root);
			((Component)_scroll.Scroll).GetComponent<RectTransform>().Fill(5f, 109f, 8f, 34f);
			for (int num = 0; num < 220; num++)
			{
				TextMeshProUGUI val = UIFactory.CreateText($"L{num}", (Transform)(object)_scroll.Content, string.Empty, 13f, Theme.Text, (TextAlignmentOptions)4097);
				TextMeshProUGUI val2 = UIFactory.CreateText($"R{num}", (Transform)(object)_scroll.Content, string.Empty, 13f, Theme.Text, (TextAlignmentOptions)4100);
				TextMeshProUGUI val3 = UIFactory.CreateText($"N{num}", (Transform)(object)_scroll.Content, string.Empty, 11f, Theme.TextDim, (TextAlignmentOptions)4100);
				((TMP_Text)val).rectTransform.Place(10f, (float)num * 20f, 330f, 20f);
				((TMP_Text)val2).rectTransform.Place(340f, (float)num * 20f, 90f, 20f);
				((TMP_Text)val3).rectTransform.Place(432f, (float)num * 20f, 92f, 20f);
				_pool[num] = (Left: val, Right: val2, Note: val3);
			}
			TextMeshProUGUI obj = UIFactory.CreateText("Footer", (Transform)(object)base.Root, "Values are what your client knows, with Bloodcraft's expertise/legacy bonuses (from the data it sends Eclipse) and PerkShop stat perks (.perk status) added. Changes a server makes without telling the client don't show here - the DPS meter measures the real result.", 11f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)obj).enableWordWrapping = true;
			((TMP_Text)obj).rectTransform.Place(14f, Height - 34f, Width - 28f, 30f);
		}

		protected override void OnShown()
		{
			if (PerkshopStats.Status == PerkshopStats.State.Unknown || (PerkshopStats.Status == PerkshopStats.State.Present && Time.realtimeSinceStartupAsDouble - PerkshopStats.LastSyncAt > 180.0))
			{
				PerkshopStats.Sync();
			}
			_nextBuildAt = 0.0;
			Refresh();
		}

		public override void Refresh()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_04be: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f6: 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_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: 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)
			if (!base.Visible)
			{
				return;
			}
			double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble;
			if (realtimeSinceStartupAsDouble < _nextBuildAt)
			{
				return;
			}
			_nextBuildAt = realtimeSinceStartupAsDouble + 0.5;
			List<StatSheet.Row> list;
			try
			{
				list = StatSheet.Build();
			}
			catch (Exception ex)
			{
				((TMP_Text)_summary).text = "Couldn't read your stats (see the log).";
				ManualLogSource log = Core.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Character sheet failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
				return;
			}
			if (list == null)
			{
				return;
			}
			float valueOrDefault = (list.FirstOrDefault((StatSheet.Row r) => (int)r.Stat == 0)?.Total).GetValueOrDefault();
			float valueOrDefault2 = (list.FirstOrDefault((StatSheet.Row r) => (int)r.Stat == 25)?.Total).GetValueOrDefault();
			float num = StatSheet.CritFactor(list, (UnitStatType)29, (UnitStatType)30);
			float num2 = StatSheet.CritFactor(list, (UnitStatType)31, (UnitStatType)32);
			string value = (BloodcraftStats.Known ? "<color=#78D478>Bloodcraft bonuses: included</color>" : "<color=#EBBA52>Bloodcraft bonuses: waiting for its data (needs Eclipse; arrives every few seconds)</color>");
			string value2 = PerkshopStats.Status switch
			{
				PerkshopStats.State.Present => $"<color=#78D478>PerkShop: {PerkshopStats.Perks.Count} stat perk(s) included</color>", 
				PerkshopStats.State.Absent => "PerkShop: not on this server", 
				_ => "<color=#EBBA52>PerkShop: checking...</color>", 
			};
			((TMP_Text)_summary).text = $"{value} · {value2}\nAverage hit power incl. crits ≈ physical {valueOrDefault * num:0.#} (x{num:0.##}) · spell {valueOrDefault2 * num2:0.#} (x{num2:0.##})";
			int num3 = 0;
			foreach (StatSheet.Row item in list)
			{
				if (num3 >= 220)
				{
					break;
				}
				float? num4 = item.Total ?? ((item.Parts.Count > 0) ? new float?(item.Parts.Where(delegate(StatSheet.Part p)
				{
					//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_0007: Unknown result type (might be due to invalid IL or missing references)
					//IL_0009: Invalid comparison between Unknown and I4
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//IL_000d: Invalid comparison between Unknown and I4
					ModificationType type = p.Type;
					return ((int)type == 3 || (int)type == 6) ? true : false;
				}).Sum((StatSheet.Part p) => p.Value)) : ((float?)null));
				float? clientValue = item.ClientValue;
				object obj;
				if (clientValue.HasValue)
				{
					float valueOrDefault3 = clientValue.GetValueOrDefault();
					clientValue = item.Total;
					if (clientValue.HasValue)
					{
						float valueOrDefault4 = clientValue.GetValueOrDefault();
						if (Math.Abs(valueOrDefault3 - valueOrDefault4) > 0.0005f)
						{
							obj = "game: " + StatSheet.FormatValue(item.Format, valueOrDefault3);
							goto IL_0380;
						}
					}
				}
				obj = ((!item.ClientValue.HasValue) ? "sum of parts" : string.Empty);
				goto IL_0380;
				IL_0380:
				string note = (string)obj;
				Set(num3++, "<b>" + item.Name + "</b>", (!num4.HasValue) ? "-" : StatSheet.FormatValue(value: num4.GetValueOrDefault(), format: item.Format), note, Theme.Text);
				foreach (StatSheet.Part part in item.Parts)
				{
					if (num3 >= 220)
					{
						break;
					}
					Color color = (part.Source.StartsWith("Bloodcraft") ? Theme.AccentHover : ((part.Source == "Base / unlisted") ? Theme.Unknown : Theme.TextDim));
					Set(num3++, "     " + part.Source, StatSheet.FormatPart(item.Format, part), string.Empty, color);
				}
			}
			for (int num5 = num3; num5 < 220; num5++)
			{
				Set(num5, string.Empty, string.Empty, string.Empty, Theme.Text);
			}
			_scroll.Content.sizeDelta = new Vector2(0f, (float)num3 * 20f + 4f);
		}

		private void Set(int i, string left, string right, string note, Color color)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			var (val, val2, val3) = _pool[i];
			if (((TMP_Text)val).text != left)
			{
				((TMP_Text)val).text = left;
			}
			if (((TMP_Text)val2).text != right)
			{
				((TMP_Text)val2).text = right;
			}
			if (((TMP_Text)val3).text != note)
			{
				((TMP_Text)val3).text = note;
			}
			((Graphic)val).color = color;
			((Graphic)val2).color = color;
		}
	}
	internal sealed class ConfirmDialog
	{
		private const float CardWidth = 340f;

		private const float CardHeight = 156f;

		private const float Pad = 16f;

		private const float ButtonWidth = 96f;

		private const float ButtonHeight = 28f;

		private readonly RectTransform _overlay;

		private readonly TextMeshProUGUI _title;

		private readonly TextMeshProUGUI _message;

		private readonly UIFactory.ButtonRef _confirm;

		private Action _onConfirm;

		public bool Visible => ((Component)_overlay).gameObject.activeSelf;

		public ConfirmDialog(RectTransform parent)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			_overlay = ((Graphic)UIFactory.CreatePanel("Confirm", (Transform)(object)parent, new Color(0f, 0f, 0f, 0.6f))).rectTransform;
			_overlay.Fill();
			RectTransform root = UIFactory.CreateCard("Card", (Transform)(object)_overlay, Theme.PanelBg, 10f).Root;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			root.pivot = val;
			root.anchorMin = (root.anchorMax = val);
			root.anchoredPosition = Vector2.zero;
			root.sizeDelta = new Vector2(340f, 156f);
			_title = UIFactory.CreateText("Title", (Transform)(object)root, string.Empty, 15f, Theme.Text, (TextAlignmentOptions)4097);
			((TMP_Text)_title).fontStyle = (FontStyles)1;
			((TMP_Text)_title).rectTransform.Place(16f, 12f, 308f, 22f);
			_message = UIFactory.CreateText("Message", (Transform)(object)root, string.Empty, 12f, Theme.TextDim, (TextAlignmentOptions)257);
			((TMP_Text)_message).enableWordWrapping = true;
			((TMP_Text)_message).rectTransform.Place(16f, 40f, 308f, 66f);
			float y = 116f;
			_confirm = UIFactory.CreateButton("Confirm", (Transform)(object)root, "OK", 13f, Confirm, 7f);
			_confirm.Rect.Place(228f, y, 96f, 28f);
			_confirm.SetColors(Theme.Accent, Theme.AccentHover);
			((TMP_Text)_confirm.Label).fontStyle = (FontStyles)1;
			UIFactory.CreateButton("Cancel", (Transform)(object)root, "Cancel", 13f, Hide, 7f).Rect.Place(124f, y, 96f, 28f);
			((Component)_overlay).gameObject.SetActive(false);
		}

		public void Show(string title, string message, string confirmLabel, Action onConfirm)
		{
			((TMP_Text)_title).text = title;
			((TMP_Text)_message).text = message;
			((TMP_Text)_confirm.Label).text = confirmLabel;
			_onConfirm = onConfirm;
			((Transform)_overlay).SetAsLastSibling();
			((Component)_overlay).gameObject.SetActive(true);
		}

		public void Hide()
		{
			_onConfirm = null;
			((Component)_overlay).gameObject.SetActive(false);
		}

		private void Confirm()
		{
			Action onConfirm = _onConfirm;
			Hide();
			onConfirm?.Invoke();
		}
	}
	internal sealed class ControlBar
	{
		public sealed class Entry
		{
			public string Label;

			public float Width = 88f;

			public Func<bool> IsOpen;

			public Action Toggle;

			public Func<bool> IsVisible;

			public Func<string> GetLabel;

			public Func<bool> IsFlashing;

			public List<Entry> Children;
		}

		private sealed class Menu
		{
			public Entry Group;

			public UIFactory.ButtonRef GroupButton;

			public RectTransform Card;

			public readonly List<(Entry Entry, UIFactory.ButtonRef Button)> Items = new List<(Entry, UIFactory.ButtonRef)>();
		}

		private const float Pad = 5f;

		private const float ButtonHeight = 26f;

		private const float GripWidth = 18f;

		private const float Gap = 4f;

		private const float Radius = 10f;

		private const float FlashSpeed = 2.5f;

		private const float ResizeWidth = 18f;

		private readonly List<(Entry Entry, UIFactory.ButtonRef Button)> _buttons = new List<(Entry, UIFactory.ButtonRef)>();

		private readonly bool[] _shown;

		private readonly RectTransform[] _gripDots = (RectTransform[])(object)new RectTransform[6];

		private readonly List<Menu> _menus = new List<Menu>();

		private Menu _openMenu;

		private float _width;

		private float _natural;

		private float _widest;

		public RectTransform Root { get; }

		public RectTransform Grip { get; }

		public RectTransform ResizeHandle { get; }

		public float Width { get; private set; }

		public static float Chrome => 54f;

		public RectTransform OpenMenu => _openMenu?.Card;

		public ControlBar(Transform parent, IEnumerable<Entry> entries)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			Root = UIFactory.CreateCard("ControlBar", parent, Theme.HudBg, 10f).Root;
			RectTransform root = Root;
			RectTransform root2 = Root;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			root2.anchorMax = val;
			root.anchorMin = val;
			Root.pivot = new Vector2(0f, 1f);
			Grip = ((Graphic)UIFactory.CreatePanel("Grip", (Transform)(object)Root, new Color(0f, 0f, 0f, 0f))).rectTransform;
			for (int i = 0; i < _gripDots.Length; i++)
			{
				_gripDots[i] = ((Graphic)UIFactory.CreateDot((Transform)(object)Grip, 0f, 0f, 3f, Theme.TextDim)).rectTransform;
			}
			foreach (Entry entry in entries)
			{
				Menu menu = null;
				if (entry.Children != null)
				{
					Menu obj = new Menu
					{
						Group = entry
					};
					menu = obj;
					Menu m = obj;
					entry.Toggle = delegate
					{
						SetMenu((_openMenu == m) ? null : m);
					};
					entry.IsOpen = () => _openMenu == m || m.Group.Children.Any((Entry c) => c.IsOpen());
				}
				UIFactory.ButtonRef buttonRef = UIFactory.CreateButton(entry.Label, (Transform)(object)Root, entry.Label, 13f, entry.Toggle, 7f);
				_buttons.Add((entry, buttonRef));
				if (menu != null)
				{
					menu.GroupButton = buttonRef;
					_menus.Add(menu);
				}
			}
			_shown = new bool[_buttons.Count];
			ResizeHandle = ((Graphic)UIFactory.CreatePanel("Resize", (Transform)(object)Root, new Color(1f, 1f, 1f, 0.06f)).Rounded(5f)).rectTransform;
			Image obj2 = UIFactory.CreatePanel("Icon", (Transform)(object)ResizeHandle, Theme.TextDim, raycast: false);
			obj2.sprite = Icons.ResizeHorizontal;
			obj2.preserveAspect = true;
			RectTransform rectTransform = ((Graphic)obj2).rectTransform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			rectTransform.pivot = val2;
			val = (rectTransform.anchorMin = (rectTransform.anchorMax = val2));
			rectTransform.anchoredPosition = Vector2.zero;
			rectTransform.sizeDelta = new Vector2(16f, 16f);
			foreach (Menu menu2 in _menus)
			{
				BuildMenu(menu2);
			}
			_width = Settings.BarWidth;
			Layout();
			Root.anchoredPosition = Settings.BarPosition;
			Refresh();
		}

		public void Resize(float width)
		{
			_width = ((width >= _natural - 0.5f) ? 0f : Mathf.Max(width, _widest));
			Layout();
		}

		public void SaveWidth()
		{
			Settings.BarWidth = _width;
		}

		public void ToggleRowColumn()
		{
			_width = ((Width >= _natural - 0.5f) ? _widest : 0f);
			Layout();
			SaveWidth();
		}

		private void Layout()
		{
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			List<int> list = new List<int>();
			_natural = 0f;
			_widest = 0f;
			for (int i = 0; i < _buttons.Count; i++)
			{
				var (entry, buttonRef) = _buttons[i];
				_shown[i] = entry.IsVisible?.Invoke() ?? true;
				((Component)buttonRef.Rect).gameObject.SetActive(_shown[i]);
				if (_shown[i])
				{
					list.Add(i);
					_natural += ((list.Count > 1) ? 4f : 0f) + entry.Width;
					_widest = Mathf.Max(_widest, entry.Width);
				}
			}
			float num = (Width = ((_width <= 0f) ? _natural : Mathf.Clamp(_width, _widest, _natural)));
			float num3 = num;
			float num4 = 27f;
			float num5 = 5f;
			int num6 = 0;
			while (num6 < list.Count)
			{
				int j = num6;
				float num7 = 0f;
				for (; j < list.Count; j++)
				{
					float num8 = ((j > num6) ? 4f : 0f) + _buttons[list[j]].Entry.Width;
					if (j > num6 && num7 + num8 > num3 + 0.5f)
					{
						break;
					}
					num7 += num8;
				}
				float num9 = 4f * (float)(j - num6 - 1);
				float num10 = (num3 - num9) / (num7 - num9);
				float num11 = num4;
				for (int k = num6; k < j; k++)
				{
					(Entry Entry, UIFactory.ButtonRef Button) tuple2 = _buttons[list[k]];
					Entry item = tuple2.Entry;
					UIFactory.ButtonRef item2 = tuple2.Button;
					float num12 = ((k == j - 1) ? (num4 + num3 - num11) : Mathf.Round(item.Width * num10));
					item2.Rect.Place(num11, num5, num12, 26f);
					num11 += num12 + 4f;
				}
				num5 += 30f;
				num6 = j;
			}
			float num13 = Mathf.Max(num5 - 4f, 31f) + 5f;
			Root.sizeDelta = new Vector2(num4 + num3 + 4f + 18f + 5f, num13);
			float num14 = num13 - 10f;
			Grip.Place(5f, 5f, 18f, num14);
			float num15 = Mathf.Ceil((num14 - 15f) / 2f);
			for (int l = 0; l < _gripDots.Length; l++)
			{
				_gripDots[l].Place(5 + l % 2 * 6, num15 + (float)(l / 2 * 6), 3f, 3f);
			}
			ResizeHandle.Place(num4 + num3 + 4f, 5f, 18f, num14);
			if (_openMenu != null)
			{
				SetMenu(_openMenu);
			}
		}

		private void BuildMenu(Menu menu)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(menu.GroupButton.Rect.sizeDelta.x, menu.Group.Children.Max((Entry entry) => entry.Width));
			menu.Card = UIFactory.CreateCard(menu.Group.Label + "Menu", (Transform)(object)Root, Theme.HudBg, 10f).Root;
			menu.Card.sizeDelta = new Vector2(num + 10f, 10f + (float)menu.Group.Children.Count * 30f - 4f);
			float num2 = 5f;
			foreach (Entry child in menu.Group.Children)
			{
				Entry c = child;
				UIFactory.ButtonRef buttonRef = UIFactory.CreateButton(c.Label, (Transform)(object)menu.Card, c.Label, 13f, delegate
				{
					SetMenu(null);
					c.Toggle();
				}, 7f);
				buttonRef.Rect.Place(5f, num2, num, 26f);
				menu.Items.Add((c, buttonRef));
				num2 += 30f;
			}
			((Component)menu.Card).gameObject.SetActive(false);
		}

		private void SetMenu(Menu menu)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_00b1: 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)
			if (_openMenu != null)
			{
				((Component)_openMenu.Card).gameObject.SetActive(false);
			}
			_openMenu = menu;
			if (menu == null)
			{
				return;
			}
			RectTransform rect = menu.GroupButton.Rect;
			float num = Mathf.Max(rect.sizeDelta.x, menu.Group.Children.Max((Entry c) => c.Width)) + 10f;
			menu.Card.Place(rect.anchoredPosition.x - 5f, 0f - rect.anchoredPosition.y + 26f + 4f, num, menu.Card.sizeDelta.y);
			foreach (var item in menu.Items)
			{
				item.Button.Rect.sizeDelta = new Vector2(num - 10f, 26f);
			}
			((Transform)menu.Card).SetAsLastSibling();
			((Component)menu.Card).gameObject.SetActive(true);
		}

		public void Refresh()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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)
			if (_openMenu != null && Input.GetMouseButtonDown(0) && !Contains(_openMenu.Card, Vector2.op_Implicit(Input.mousePosition)) && !Contains(_openMenu.GroupButton.Rect, Vector2.op_Implicit(Input.mousePosition)))
			{
				SetMenu(null);
			}
			for (int i = 0; i < _buttons.Count; i++)
			{
				if ((_buttons[i].Entry.IsVisible?.Invoke() ?? true) != _shown[i])
				{
					Layout();
					break;
				}
			}
			float pulse = Mathf.PingPong(Time.realtimeSinceStartup * 2.5f * 2f, 1f);
			for (int j = 0; j < _buttons.Count; j++)
			{
				if (_shown[j])
				{
					Restyle(_buttons[j].Entry, _buttons[j].Button, pulse);
				}
			}
			if (_openMenu == null)
			{
				return;
			}
			foreach (var (entry, button) in _openMenu.Items)
			{
				Restyle(entry, button, pulse);
			}
		}

		private static void Restyle(Entry entry, UIFactory.ButtonRef button, float pulse)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_00ac: 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)
			if (entry.GetLabel != null)
			{
				string text = entry.GetLabel();
				if (((TMP_Text)button.Label).text != text)
				{
					((TMP_Text)button.Label).text = text;
				}
			}
			Func<bool> isFlashing = entry.IsFlashing;
			if (isFlashing != null && isFlashing())
			{
				button.Style = "flash";
				button.SetColors(Color.Lerp(Theme.Accent, Theme.Due, pulse), Theme.AccentHover);
				return;
			}
			string text2 = (entry.IsOpen() ? "open" : "closed");
			if (!(button.Style == text2))
			{
				button.Style = text2;
				if (text2 == "open")
				{
					button.SetColors(Theme.Accent, Theme.AccentHover);
				}
				else
				{
					button.SetColors(Theme.Button, Theme.ButtonHover);
				}
			}
		}

		private static bool Contains(RectTransform rect, Vector2 screenPoint)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (((Component)rect).gameObject.activeInHierarchy)
			{
				return RectTransformUtility.RectangleContainsScreenPoint(rect, screenPoint, (Camera)null);
			}
			return false;
		}
	}
	internal sealed class CooldownPanel : Window
	{
		private const float PanelWidth = 720f;

		private const float RowHeight = 24f;

		private const int Rows = 12;

		private const float HeaderY = 103f;

		private const float RowsTop = 127f;

		private const float FooterHeight = 46f;

		private static readonly float[] ColX = new float[9] { 14f, 186f, 238f, 296f, 354f, 414f, 494f, 556f, 636f };

		private static readonly float[] ColW = new float[9] { 168f, 50f, 54f, 54f, 56f, 76f, 58f, 76f, 70f };

		private readonly TextMeshProUGUI _summary;

		private readonly TextMeshProUGUI[][] _cells = new TextMeshProUGUI[12][];

		private readonly TextMeshProUGUI _empty;

		public override Vector2 SavedPosition
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return Settings.CooldownPanelPosition;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Settings.CooldownPanelPosition = value;
			}
		}

		public CooldownPanel(Transform parent)
			: base("Cooldowns", parent, "Cooldown tester", "use a skill, see its real cooldown", 720f, 469f)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			_summary = UIFactory.CreateText("Summary", (Transform)(object)base.Root, string.Empty, 12f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_summary).enableWordWrapping = true;
			((TMP_Text)_summary).rectTransform.Place(14f, 47f, Width - 130f, 48f);
			UIFactory.CreateButton("Reset", (Transform)(object)base.Root, "Reset", 12f, CooldownTester.Reset, 12f).Rect.Place(Width - 100f, 51f, 88f, 24f);
			string[] array = new string[9] { "Ability", "Type", "Base", "Game", "Last", "Avg (n)", "Left", "As rate", "As reduct." };
			for (int i = 0; i < array.Length; i++)
			{
				TextMeshProUGUI obj = UIFactory.CreateText(array[i], (Transform)(object)base.Root, array[i].ToUpperInvariant(), 10f, Theme.TextDim, (TextAlignmentOptions)((i == 0) ? 4097 : 4100));
				((TMP_Text)obj).characterSpacing = 1.5f;
				((TMP_Text)obj).rectTransform.Place(ColX[i], 103f, ColW[i], 20f);
			}
			UIFactory.CreateDivider((Transform)(object)base.Root, 12f, 123f, Width - 24f);
			for (int j = 0; j < 12; j++)
			{
				_cells[j] = (TextMeshProUGUI[])(object)new TextMeshProUGUI[ColX.Length];
				for (int k = 0; k < ColX.Length; k++)
				{
					TextMeshProUGUI val = UIFactory.CreateText($"C{j}_{k}", (Transform)(object)base.Root, string.Empty, 12f, Theme.Text, (TextAlignmentOptions)((k == 0) ? 4097 : 4100));
					((TMP_Text)val).rectTransform.Place(ColX[k], 127f + (float)j * 24f, ColW[k], 24f);
					_cells[j][k] = val;
				}
			}
			_empty = UIFactory.CreateText("Empty", (Transform)(object)base.Root, "Use a weapon skill or spell - it shows up here, and its cooldown is timed until it's ready again.", 12f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_empty).rectTransform.Place(14f, 127f, Width - 28f, 24f);
			TextMeshProUGUI obj2 = UIFactory.CreateText("Footer", (Transform)(object)base.Root, "Base = the skill's unmodified cooldown. Game = what the game applied. Last/Avg = measured until ready. As rate / As reduct. = the bonus that measurement implies if the stat works as base ÷ (1 + bonus) or base × (1 − bonus). Green = more than your client's stat shows (bonuses beyond the cap, applied by the server).", 11f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)obj2).enableWordWrapping = true;
			((TMP_Text)obj2).rectTransform.Place(14f, Height - 46f, Width - 28f, 42f);
		}

		public override void Refresh()
		{
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			if (!base.Visible)
			{
				return;
			}
			(float, float, float, float) tuple = CooldownTester.ClientRates();
			((TMP_Text)_summary).text = $"Your client's cooldown stats:  weapon <b>{tuple.Item1 * 100f:0.#}%</b> · spell <b>{tuple.Item2 * 100f:0.#}%</b> · ultimate {tuple.Item3 * 100f:0.#}% · all {tuple.Item4 * 100f:0.#}%\n" + "Compare a skill's implied bonus with its stat: the closer column is how the stat works.";
			List<CooldownTester.Ability> list = CooldownTester.Abilities.ToList();
			((Component)_empty).gameObject.SetActive(list.Count == 0);
			for (int i = 0; i < 12; i++)
			{
				TextMeshProUGUI[] array = _cells[i];
				if (i >= list.Count)
				{
					TextMeshProUGUI[] array2 = array;
					for (int j = 0; j < array2.Length; j++)
					{
						((TMP_Text)array2[j]).text = string.Empty;
					}
					continue;
				}
				CooldownTester.Ability ability = list[i];
				float num;
				switch (ability.Kind)
				{
				case CooldownTester.Kind.Weapon:
					(num, _, _, _) = tuple;
					break;
				case CooldownTester.Kind.Spell:
					num = tuple.Item2;
					break;
				default:
					num = float.NaN;
					break;
				}
				float stat = num;
				float? averageMeasured = ability.AverageMeasured;
				double value = CooldownTester.Remaining(ability);
				((TMP_Text)array[0]).text = ability.Name;
				((TMP_Text)array[1]).text = ability.Kind.ToString().ToLowerInvariant();
				((TMP_Text)array[2]).text = Seconds(ability.BaseCooldown);
				((TMP_Text)array[3]).text = Seconds(ability.GameCooldown);
				TextMeshProUGUI obj = array[4];
				float? lastMeasured = ability.LastMeasured;
				object text;
				if (lastMeasured.HasValue)
				{
					float valueOrDefault = lastMeasured.GetValueOrDefault();
					text = Seconds(valueOrDefault) + (ability.Adjusted ? "*" : "");
				}
				else
				{
					text = "-";
				}
				((TMP_Text)obj).text = (string)text;
				TextMeshProUGUI obj2 = array[5];
				object text2;
				if (averageMeasured.HasValue)
				{
					float valueOrDefault2 = averageMeasured.GetValueOrDefault();
					text2 = $"{Seconds(valueOrDefault2)} ({ability.Samples.Count})";
				}
				else
				{
					text2 = "-";
				}
				((TMP_Text)obj2).text = (string)text2;
				((TMP_Text)array[6]).text = (ability.Running ? $"{value:0.0}s" : "ready");
				((Graphic)array[6]).color = (ability.Running ? Theme.Respawning : Theme.Alive);
				if (averageMeasured.HasValue)
				{
					float valueOrDefault3 = averageMeasured.GetValueOrDefault();
					if (valueOrDefault3 > 0f && ability.BaseCooldown > 0f)
					{
						float num2 = ability.BaseCooldown / valueOrDefault3 - 1f;
						float num3 = 1f - valueOrDefault3 / ability.BaseCooldown;
						((TMP_Text)array[7]).text = $"{num2 * 100f:0.#}%";
						((TMP_Text)array[8]).text = $"{num3 * 100f:0.#}%";
						((Graphic)array[7]).color = Highlight(num2, stat);
						((Graphic)array[8]).color = Highlight(num3, stat);
						continue;
					}
				}
				TextMeshProUGUI obj3 = array[7];
				string text3 = (((TMP_Text)array[8]).text = "-");
				((TMP_Text)obj3).text = text3;
				TextMeshProUGUI obj4 = array[7];
				Color color = (((Graphic)array[8]).color = Theme.TextDim);
				((Graphic)obj4).color = color;
			}
		}

		private static Color Highlight(float implied, float stat)
		{
			//IL_001e: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!float.IsNaN(stat))
			{
				if (!(implied > stat + 0.02f))
				{
					return Theme.Text;
				}
				return Theme.Alive;
			}
			return Theme.Text;
		}

		private static string Seconds(float s)
		{
			if (!(s > 0f))
			{
				return "-";
			}
			return $"{s:0.00}s";
		}
	}
	internal sealed class DpsPanel : Window
	{
		private const float PanelWidth = 600f;

		private const float RowHeight = 24f;

		private const int AbilityRows = 12;

		private const int FightRows = 6;

		private const float HeaderY = 91f;

		private const float AbilityTop = 115f;

		private const float FightsY = 415f;

		private const float FightsTop = 439f;

		private static readonly float[] ColX = new float[6] { 14f, 250f, 334f, 410f, 466f, 522f };

		private static readonly float[] ColW = new float[6] { 230f, 78f, 70f, 50f, 50f, 64f };

		private readonly TextMeshProUGUI _summary;

		private readonly UIFactory.ButtonRef _live;

		private readonly TextMeshProUGUI[][] _abilityCells = new TextMeshProUGUI[12][];

		private readonly UIFactory.ButtonRef[] _fightButtons = new UIFactory.ButtonRef[6];

		private readonly TextMeshProUGUI[][] _fightCells = new TextMeshProUGUI[6][];

		private readonly TextMeshProUGUI _noFights;

		private DamageMeter.Fight _selected;

		public override Vector2 SavedPosition
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return Settings.DpsPanelPosition;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Settings.DpsPanelPosition = value;
			}
		}

		public DpsPanel(Transform parent)
			: base("Dps", parent, "DPS meter", "damage you deal, per fight", 600f, 623f)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
			_summary = UIFactory.CreateText("Summary", (Transform)(object)base.Root, string.Empty, 14f, Theme.Text, (TextAlignmentOptions)4097);
			((TMP_Text)_summary).rectTransform.Place(14f, 51f, Width - 190f, 28f);
			_live = UIFactory.CreateButton("Live", (Transform)(object)base.Root, "Live", 12f, delegate
			{
				_selected = null;
			}, 12f);
			_live.Rect.Place(Width - 172f, 53f, 70f, 24f);
			UIFactory.CreateButton("Reset", (Transform)(object)base.Root, "Reset", 12f, delegate
			{
				_selected = null;
				DamageMeter.Reset();
			}, 12f).Rect.Place(Width - 96f, 53f, 84f, 24f);
			string[] array = new string[6] { "Ability", "Damage", "DPS", "Hits", "Crit", "Share" };
			for (int num = 0; num < array.Length; num++)
			{
				Header(array[num], num, 91f);
			}
			UIFactory.CreateDivider((Transform)(object)base.Root, 12f, 111f, Width - 24f);
			for (int num2 = 0; num2 < 12; num2++)
			{
				_abilityCells[num2] = (TextMeshProUGUI[])(object)new TextMeshProUGUI[ColX.Length];
				for (int num3 = 0; num3 < ColX.Length; num3++)
				{
					TextMeshProUGUI val = UIFactory.CreateText($"A{num2}_{num3}", (Transform)(object)base.Root, string.Empty, 13f, Theme.Text, (TextAlignmentOptions)((num3 == 0) ? 4097 : 4100));
					((TMP_Text)val).rectTransform.Place(ColX[num3], 115f + (float)num2 * 24f, ColW[num3], 24f);
					_abilityCells[num2][num3] = val;
				}
			}
			TextMeshProUGUI obj = UIFactory.CreateText("Recent", (Transform)(object)base.Root, "RECENT FIGHTS  (click one to show it)", 11f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)obj).characterSpacing = 3f;
			((TMP_Text)obj).rectTransform.Place(14f, 415f, Width - 28f, 20f);
			UIFactory.CreateDivider((Transform)(object)base.Root, 12f, 435f, Width - 24f);
			_noFights = UIFactory.CreateText("NoFights", (Transform)(object)base.Root, "Fights show up here once they end (a few seconds after your last hit).", 12f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_noFights).rectTransform.Place(14f, 439f, Width - 28f, 24f);
			for (int num4 = 0; num4 < 6; num4++)
			{
				int index = num4;
				UIFactory.ButtonRef buttonRef = UIFactory.CreateButton($"Fight{num4}", (Transform)(object)base.Root, string.Empty, 12f, delegate
				{
					Select(index);
				}, 6f, outline: false);
				buttonRef.Rect.Place(8f, 439f + (float)num4 * 24f, Width - 16f, 22f);
				_fightButtons[num4] = buttonRef;
				float[] array2 = new float[5] { 8f, 70f, 330f, 400f, 490f };
				float[] array3 = new float[5] { 56f, 250f, 64f, 84f, 80f };
				_fightCells[num4] = (TextMeshProUGUI[])(object)new TextMeshProUGUI[array2.Length];
				for (int num5 = 0; num5 < array2.Length; num5++)
				{
					string name = $"F{num5}";
					Transform rect = (Transform)(object)buttonRef.Rect;
					bool flag = (uint)num5 <= 1u;
					TextMeshProUGUI val2 = UIFactory.CreateText(name, rect, string.Empty, 12f, Theme.Text, (TextAlignmentOptions)(flag ? 4097 : 4100));
					((TMP_Text)val2).rectTransform.Place(array2[num5], 0f, array3[num5], 22f);
					_fightCells[num4][num5] = val2;
				}
			}
		}

		private void Header(string text, int column, float y)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = UIFactory.CreateText(text, (Transform)(object)base.Root, text.ToUpperInvariant(), 11f, Theme.TextDim, (TextAlignmentOptions)((column == 0) ? 4097 : 4100));
			((TMP_Text)obj).characterSpacing = 2f;
			((TMP_Text)obj).rectTransform.Place(ColX[column], y, ColW[column], 20f);
		}

		private void Select(int index)
		{
			if (index < DamageMeter.History.Count)
			{
				DamageMeter.Fight fight = DamageMeter.History[index];
				_selected = ((_selected == fight) ? null : fight);
			}
		}

		public override void Refresh()
		{
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: 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_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0479: Unknown result type (might be due to invalid IL or missing references)
			if (!base.Visible)
			{
				return;
			}
			if (_selected != null && !DamageMeter.History.Contains(_selected))
			{
				_selected = null;
			}
			DamageMeter.Fight fight = _selected ?? DamageMeter.Latest;
			bool flag = _selected == null && DamageMeter.Current != null;
			((TMP_Text)_summary).text = ((fight == null) ? "No damage yet - hit something." : $"{(flag ? "Fighting" : ((_selected != null) ? $"Fight at {fight.StartedAt:HH:mm}" : "Last fight"))} · {FormatTime(fight.Seconds)} · <b>{fight.Dps:N0} DPS</b> · {ExperienceTracker.Format(fight.Damage)} vs {fight.MainTarget}");
			((Graphic)_summary).color = (flag ? Theme.AccentHover : Theme.Text);
			_live.SetColors((_selected == null) ? Theme.Accent : Theme.Button, (_selected == null) ? Theme.AccentHover : Theme.ButtonHover);
			List<DamageMeter.Line> list = fight?.Lines.Values.OrderByDescending((DamageMeter.Line l) => l.Damage).ToList() ?? new List<DamageMeter.Line>();
			for (int num = 0; num < 12; num++)
			{
				TextMeshProUGUI[] array = _abilityCells[num];
				if (num >= list.Count)
				{
					TextMeshProUGUI[] array2 = array;
					for (int num2 = 0; num2 < array2.Length; num2++)
					{
						((TMP_Text)array2[num2]).text = string.Empty;
					}
					continue;
				}
				DamageMeter.Line line = list[num];
				((TMP_Text)array[0]).text = line.Name;
				((TMP_Text)array[1]).text = ExperienceTracker.Format(line.Damage);
				((TMP_Text)array[2]).text = (line.Damage / fight.Seconds).ToString("N0");
				((TMP_Text)array[3]).text = line.Hits.ToString();
				((TMP_Text)array[4]).text = ((line.Hits == 0) ? "-" : $"{100.0 * (double)line.Crits / (double)line.Hits:0}%");
				((TMP_Text)array[5]).text = $"{100.0 * line.Damage / Math.Max(1.0, fight.Damage):0}%";
				((Graphic)array[0]).color = ((line.Name == "Familiar / minions") ? Theme.Respawning : Theme.Text);
			}
			IReadOnlyList<DamageMeter.Fight> history = DamageMeter.History;
			((Component)_noFights).gameObject.SetActive(history.Count == 0);
			for (int num3 = 0; num3 < 6; num3++)
			{
				bool flag2 = num3 < history.Count;
				((Component)_fightButtons[num3].Rect).gameObject.SetActive(flag2);
				if (flag2)
				{
					DamageMeter.Fight fight2 = history[num3];
					TextMeshProUGUI[] obj = _fightCells[num3];
					((TMP_Text)obj[0]).text = fight2.StartedAt.ToString("HH:mm");
					((TMP_Text)obj[1]).text = fight2.MainTarget;
					((TMP_Text)obj[2]).text = FormatTime(fight2.Seconds);
					((TMP_Text)obj[3]).text = $"{fight2.Dps:N0} DPS";
					((TMP_Text)obj[4]).text = ExperienceTracker.Format(fight2.Damage);
					Color normal = (Color)((fight2 == _selected) ? Theme.RowHunted : ((num3 % 2 == 1) ? Theme.RowAlt : new Color(0f, 0f, 0f, 0f)));
					_fightButtons[num3].SetColors(normal, Theme.ButtonHover);
				}
			}
		}

		private static string FormatTime(double seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			if (timeSpan.TotalHours >= 1.0)
			{
				return $"{(int)timeSpan.TotalHours}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}";
			}
			return $"{(int)timeSpan.TotalMinutes}:{timeSpan.Seconds:00}";
		}
	}
	internal sealed class ExperiencePanel : Window
	{
		private sealed class Row
		{
			public ExperienceTracker.Group Group;

			public RectTransform Rect;

			public TextMeshProUGUI[] Cells;
		}

		private const float PanelWidth = 660f;

		private const float RowHeight = 28f;

		private const float LogY = 83f;

		private const float HeaderY = 121f;

		private const float ListTop = 147f;

		private const float FooterHeight = 34f;

		private static readonly float[] ColX = new float[7] { 12f, 184f, 260f, 334f, 408f, 488f, 562f };

		private static readonly float[] ColW = new float[7] { 168f, 72f, 70f, 70f, 76f, 70f, 60f };

		private readonly TextMeshProUGUI _current;

		private readonly TextMeshProUGUI _log;

		private readonly UIFactory.ScrollRef _scroll;

		private readonly TextMeshProUGUI _empty;

		private readonly List<Row> _rows = new List<Row>();

		private ExperienceTracker.Group _builtNewest;

		private int _builtCount = -1;

		public override Vector2 SavedPosition
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return Settings.XpPanelPosition;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Settings.XpPanelPosition = value;
			}
		}

		public ExperiencePanel(Transform parent)
			: base("Experience", parent, "Experience", "per hour, by prestige", 660f, 420f)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			_current = UIFactory.CreateText("Current", (Transform)(object)base.Root, string.Empty, 14f, Theme.Text, (TextAlignmentOptions)4097);
			((TMP_Text)_current).rectTransform.Place(14f, 51f, Width - 220f, 26f);
			UIFactory.CreateButton("Sync", (Transform)(object)base.Root, "Sync levels", 12f, ExperienceTracker.Sync, 12f).Rect.Place(Width - 204f, 51f, 96f, 24f);
			UIFactory.CreateButton("Reset", (Transform)(object)base.Root, "Reset row", 12f, ExperienceTracker.ResetCurrent, 12f).Rect.Place(Width - 102f, 51f, 90f, 24f);
			_log = UIFactory.CreateText("Log", (Transform)(object)base.Root, string.Empty, 12f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_log).rectTransform.Place(14f, 83f, Width - 200f, 26f);
			UIFactory.CreateButton("ToggleLog", (Transform)(object)base.Root, "Toggle .lvl log", 12f, ExperienceTracker.ToggleBloodcraftLog, 12f).Rect.Place(Width - 162f, 83f, 150f, 24f);
			string[] array = new string[7] { "Prestige", "Active", "Quests/h", "Mobs/h", "V Blood/h", "Total/h", "XP" };
			for (int i = 0; i < array.Length; i++)
			{
				TextMeshProUGUI obj = UIFactory.CreateText(array[i], (Transform)(object)base.Root, array[i].ToUpperInvariant(), 11f, Theme.TextDim, (TextAlignmentOptions)((i == 0) ? 4097 : 4100));
				((TMP_Text)obj).characterSpacing = 2f;
				((TMP_Text)obj).rectTransform.Place(ColX[i] + 5f, 121f, ColW[i], 20f);
			}
			UIFactory.CreateDivider((Transform)(object)base.Root, 12f, 143f, Width - 24f);
			_scroll = UIFactory.CreateScrollView("Groups", (Transform)(object)base.Root);
			((Component)_scroll.Scroll).GetComponent<RectTransform>().Fill(5f, 147f, 8f, 34f);
			_empty = UIFactory.CreateText("Empty", (Transform)(object)_scroll.Content, "No experience counted yet. Turn on Bloodcraft's XP log with the button above, then go kill something.", 12f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_empty).rectTransform.Place(10f, 4f, Width - 40f, 28f);
			TextMeshProUGUI obj2 = UIFactory.CreateText("Footer", (Transform)(object)base.Root, "Counts Bloodcraft's +XP lines: quest rewards, the biggest gain when a V Blood dies near you, and everything else as mobs. Time only counts while you're gaining XP. A prestige or exo starts a new row.", 11f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)obj2).enableWordWrapping = true;
			((TMP_Text)obj2).rectTransform.Place(14f, Height - 34f, Width - 28f, 30f);
		}

		private void RebuildRows()
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: 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)
			foreach (Row row in _rows)
			{
				Object.Destroy((Object)(object)((Component)row.Rect).gameObject);
			}
			_rows.Clear();
			int num = 0;
			foreach (ExperienceTracker.Group group in ExperienceTracker.Groups)
			{
				RectTransform val = UIFactory.CreateRect("Group", (Transform)(object)_scroll.Content);
				val.Place(2f, (float)num * 28f + 1f, Width - 30f, 26f);
				if (num % 2 == 1)
				{
					((Graphic)UIFactory.CreatePanel("Alt", (Transform)(object)val, Theme.RowAlt, raycast: false).Rounded(6f)).rectTransform.Fill();
				}
				TextMeshProUGUI[] array = (TextMeshProUGUI[])(object)new TextMeshProUGUI[ColX.Length];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = UIFactory.CreateText($"Cell{i}", (Transform)(object)val, string.Empty, 13f, Theme.Text, (TextAlignmentOptions)((i == 0) ? 4097 : 4100));
					((TMP_Text)array[i]).rectTransform.Place(ColX[i] - 2f + 5f, 0f, ColW[i], 26f);
				}
				_rows.Add(new Row
				{
					Group = group,
					Rect = val,
					Cells = array
				});
				num++;
			}
			((Component)_empty).gameObject.SetActive(_rows.Count == 0);
			_scroll.Content.sizeDelta = new Vector2(0f, (float)Math.Max(1, _rows.Count) * 28f);
			_builtCount = _rows.Count;
			_builtNewest = ExperienceTracker.Current;
		}

		public override void Refresh()
		{
			//IL_00eb: 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)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			if (!base.Visible)
			{
				return;
			}
			if (_builtCount != ExperienceTracker.Groups.Count() || _builtNewest != ExperienceTracker.Current)
			{
				RebuildRows();
			}
			ExperienceTracker.Group current = ExperienceTracker.Current;
			((TMP_Text)_current).text = ((current == null) ? "Current: waiting for experience" : $"Current: {current.Label} · {ExperienceTracker.Format(ExperienceTracker.CurrentRate)} XP/h");
			TextMeshProUGUI log = _log;
			TextMeshProUGUI log2 = _log;
			bool? logEnabled = ExperienceTracker.LogEnabled;
			(string, Color) tuple = ((!logEnabled.HasValue) ? ("Bloodcraft XP log: not seen yet this session", Theme.TextDim) : ((logEnabled != true) ? ("Bloodcraft XP log: off - turn it on to count XP", Theme.Due) : ("Bloodcraft XP log: on", Theme.Alive)));
			(string, Color) tuple2 = tuple;
			((TMP_Text)log).text = tuple2.Item1;
			((Graphic)log2).color = tuple2.Item2;
			foreach (Row row in _rows)
			{
				ExperienceTracker.Group obj = row.Group;
				bool flag = obj == current;
				((TMP_Text)row.Cells[0]).text = obj.Label;
				((TMP_Text)row.Cells[1]).text = FormatTime(obj.ActiveSeconds);
				((TMP_Text)row.Cells[2]).text = Rate(obj, obj.Quest);
				((TMP_Text)row.Cells[3]).text = Rate(obj, obj.Mobs);
				((TMP_Text)row.Cells[4]).text = Rate(obj, obj.VBlood);
				((TMP_Text)row.Cells[5]).text = Rate(obj, obj.Total);
				((TMP_Text)row.Cells[6]).text = ExperienceTracker.Format(obj.Total);
				TextMeshProUGUI[] cells = row.Cells;
				for (int i = 0; i < cells.Length; i++)
				{
					((Graphic)cells[i]).color = (flag ? Theme.Text : Theme.TextDim);
				}
				((Graphic)row.Cells[5]).color = (flag ? Theme.AccentHover : Theme.TextDim);
			}
		}

		private static string Rate(ExperienceTracker.Group g, double xp)
		{
			if (!(g.ActiveSeconds < 60.0))
			{
				return ExperienceTracker.Format(g.PerHour(xp));
			}
			return "-";
		}

		private static string FormatTime(double seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
			if (timeSpan.TotalHours >= 1.0)
			{
				return $"{(int)timeSpan.TotalHours}h {timeSpan.Minutes:00}m";
			}
			return $"{timeSpan.Minutes}m {timeSpan.Seconds:00}s";
		}
	}
	internal sealed class FamiliarPanel : Window
	{
		private const float PanelWidth = 420f;

		private const float RowHeight = 30f;

		private const float SummonWidth = 96f;

		private const float ActionsY = 91f;

		private const float StatusY = 121f;

		private const float SavedY = 151f;

		private const float ListTop = 177f;

		private const float FooterHeight = 48f;

		private const float KeyWidth = 78f;

		private const float TabWidth = 84f;

		private const float AllRowHeight = 40f;

		private const double ConfirmSeconds = 4.0;

		private const double NoteSeconds = 5.0;

		private const string SavedFooter = "Binds with Bloodcraft's .fam sb (partial names work, not in combat); summoning the bound familiar again calls/dismisses it (.fam t). Hotkeys: click a key button and press a key (Esc cancels, Backspace clears). Use keys the game doesn't, e.g. F5-F12, numpad or Ctrl+key.";

		private const string AllFooter = "List All reads every box with Bloodcraft's .fam boxes / cb / l (replies hidden) and then selects your box again. Save adds a familiar to the quick summon list. Delete removes it from its box for good (.fam r).";

		private readonly TMP_InputField _input;

		private readonly TextMeshProUGUI _bound;

		private readonly TextMeshProUGUI _status;

		private readonly TextMeshProUGUI _empty;

		private readonly UIFactory.ScrollRef _scroll;

		private readonly UIFactory.ScrollRef _allScroll;

		private readonly TextMeshProUGUI _allEmpty;

		private readonly TextMeshProUGUI _catalogStatus;

		private readonly TextMeshProUGUI _footer;

		private readonly UIFactory.ButtonRef _savedTab;

		private readonly UIFactory.ButtonRef _allTab;

		private readonly List<RectTransform> _allRows = new List<RectTransform>();

		private readonly Dictionary<FamiliarCatalog.Familiar, UIFactory.ButtonRef> _deleteButtons = new Dictionary<FamiliarCatalog.Familiar, UIFactory.ButtonRef>();

		private FamiliarCatalog.Familiar _confirmDelete;

		private double _confirmUntil;

		private readonly List<RectTransform> _rows = new List<RectTransform>();

		private readonly Dictionary<string, UIFactory.ButtonRef> _keyButtons = new Dictionary<string, UIFactory.ButtonRef>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, TextMeshProUGUI> _nameLabels = new Dictionary<string, TextMeshProUGUI>(StringComparer.OrdinalIgnoreCase);

		private string _capturing;

		private string _note;

		private double _noteUntil;

		public bool Capturing => _capturing != null;

		public override Vector2 SavedPosition
		{
			get
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return Settings.FamiliarPanelPosition;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				Settings.FamiliarPanelPosition = value;
			}
		}

		public FamiliarPanel(Transform parent)
			: base("Familiars", parent, "Familiars", "quick summon", 420f, 490f)
		{
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: 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_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_047d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
			float width = Width - 24f - 96f - 8f;
			_input = UIFactory.CreateInputField("Name", (Transform)(object)base.Root, "Familiar name...", 14f, SummonTyped, 48);
			((Component)_input).GetComponent<RectTransform>().Place(12f, 51f, width, 32f);
			UIFactory.ButtonRef buttonRef = UIFactory.CreateButton("Summon", (Transform)(object)base.Root, "Summon", 14f, delegate
			{
				SummonTyped(_input.text);
			}, 8f);
			buttonRef.Rect.Place(Width - 12f - 96f, 51f, 96f, 32f);
			buttonRef.SetColors(Theme.Accent, Theme.AccentHover);
			((TMP_Text)buttonRef.Label).fontStyle = (FontStyles)1;
			UIFactory.CreateButton("CallDismiss", (Transform)(object)base.Root, "Call / Dismiss", 13f, delegate
			{
				FamiliarService.ToggleActive();
			}, 13f).Rect.Place(12f, 91f, 124f, 26f);
			_bound = UIFactory.CreateText("Bound", (Transform)(object)base.Root, string.Empty, 13f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_bound).rectTransform.Place(146f, 91f, Width - 158f, 26f);
			_status = UIFactory.CreateText("Status", (Transform)(object)base.Root, string.Empty, 12f, Theme.TextDim, (TextAlignmentOptions)4097);
			((TMP_Text)_status).rectTransform.Place(14f, 121f, Width - 28f, 22f);
			_savedTab = UIFactory.CreateButton("SavedTab", (Transform)(object)base.Root, "Saved", 12f, delegate
			{
				ShowAll(all: false);
			});
			_savedTab.Rect.Place(12f, 148f, 84f, 22f);
			_allTab = UIFactory.CreateButton("ListAll", (Transform)(object)base.Root, "List All", 12f, ListAll);
			_allTab.Rect.Place(102f, 148f, 84f, 22f);
			float num = 198f;
			_catalogStatus = UIFactory.CreateText("CatalogStatus", (Transform)(object)base.Root, string.Empty, 11f, Theme.TextDim, (TextAlignmentOptions)4100);
			((TMP_Text)_catalogStatus).overflowMode = (TextOverflowModes)1;
			((TMP_Text)_catalogStatus).rectTransform.Place(num, 148f, Width - 14f - num, 22f);
			UIFact