Decompiled source of UniversalCooldownUI v1.1.5

plugins\UniversalCooldownUI.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using ProjectM.Network;
using ProjectM.UI;
using TMPro;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("UniversalCooldownUI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Bloodcraft fix for V Rising 1.1.15: cooldown recovery in tooltips, weapon bonuses and a native Blood tab in the character window.")]
[assembly: AssemblyFileVersion("1.1.5.0")]
[assembly: AssemblyInformationalVersion("1.1.5")]
[assembly: AssemblyProduct("UniversalCooldownUI")]
[assembly: AssemblyTitle("UniversalCooldownUI")]
[assembly: AssemblyVersion("1.1.5.0")]
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;
		}
	}
}
namespace UniversalCooldownUI
{
	internal static class BuffsTab
	{
		internal sealed class Section
		{
			public string Kind = "";

			public string Title = "";

			public readonly List<KeyValuePair<string, string>> Rows = new List<KeyValuePair<string, string>>();
		}

		private const string DataFilePrefix = "universalcooldown_buffs";

		private static readonly Color TextColor = new Color(1f, 1f, 1f, 0.92f);

		private static Color _green = new Color(0.42f, 0.85f, 0.33f);

		private static InventorySubMenu _menu;

		private static GameObject _root;

		private static Transform _content;

		private static CanvasGroup _windowGroup;

		private static SimpleStunButton _button;

		private static TMP_Text _buttonLabel;

		private static RectTransform _buttonRect;

		private static Sprite _normalSprite;

		private static Sprite _selectedSprite;

		private static Color _normalColor = Color.white;

		private static Color _selectedColor = Color.white;

		private static Image _highlight;

		private static GameObject _headerTemplate;

		private static GameObject _dividerTemplate;

		private static GameObject _rowTemplate;

		private static readonly List<SimpleStunButton> VanillaButtons = new List<SimpleStunButton>();

		private static readonly List<(TMP_Text Text, string Value)> Enforced = new List<(TMP_Text, string)>();

		private static List<Section> _lastSections = new List<Section>();

		private static List<Section> _remoteSections = new List<Section>();

		private static float _lastDataTime = -999f;

		private static bool _built;

		private static bool _active;

		private static bool _nativeTab;

		private static int _tabIndex = -1;

		private static int _lastTab = -99;

		private static int _lastClickFrame = -1;

		private static int _layoutFrames;

		private static string _signature = string.Empty;

		private static float _nextRefresh;

		private static int _tickFrame = -1;

		private static float _nextEnforce;

		private static DateTime _fileStamp = DateTime.MinValue;

		private static ulong _localId;

		private static float _nextIdTry;

		private static int _warmStage;

		private static int _warmFrame;

		private static int _warmPrevTab;

		private static int _warmRetryAt;

		internal static ulong LocalSteamId => _localId;

		internal static void Bind(InventorySubMenu menu)
		{
			if ((Object)(object)menu != (Object)null)
			{
				_menu = menu;
			}
		}

		internal static void Rebind(InventorySubMenu menu)
		{
			try
			{
				CleanupExisting(menu);
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] cleanup: " + ex.Message));
			}
			ResetState();
			_remoteSections.Clear();
			_lastSections.Clear();
			_signature = string.Empty;
			_fileStamp = DateTime.MinValue;
			_lastDataTime = -999f;
			_warmStage = 0;
			_warmRetryAt = 0;
			_menu = menu;
		}

		internal static void Tick(World world)
		{
			try
			{
				if ((Object)(object)_menu == (Object)null || !Plugin.BloodTab.Value)
				{
					return;
				}
				ChatSync.SetWorld(world);
				ChatSync.AutoPoll();
				if (_localId == 0L && world != null)
				{
					TryResolveLocalId(world);
				}
				int frameCount = Time.frameCount;
				if (frameCount == _tickFrame)
				{
					return;
				}
				_tickFrame = frameCount;
				if (_built && ((Object)(object)_root == (Object)null || (Object)(object)_button == (Object)null))
				{
					ResetState();
				}
				bool activeInHierarchy = ((Component)_menu).gameObject.activeInHierarchy;
				if (activeInHierarchy && !_built)
				{
					TryBuild();
				}
				if (_built)
				{
					WarmUpTemplates();
					if (activeInHierarchy)
					{
						PollClicks();
					}
					RefreshFromServer();
					ApplyNativeState();
					EnforceTexts();
					if (_active && _layoutFrames > 0)
					{
						_layoutFrames--;
						RebuildLayout();
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] tick: " + ex.Message));
			}
		}

		private static void ApplyNativeState()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			int num = -1;
			try
			{
				num = _menu.CurrentTab;
			}
			catch
			{
			}
			_lastTab = num;
			if (!_nativeTab || _tabIndex < 0)
			{
				return;
			}
			bool flag = num == _tabIndex;
			if (flag && !_active)
			{
				_active = true;
				Rebuild(ReadServerSections());
				_layoutFrames = 3;
				if (Time.time - _lastDataTime > 10f)
				{
					ChatSync.Request();
				}
				LogLayout();
				ManualLogSource l = Plugin.L;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BuffsTab] opened by the game (tab=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_tabIndex);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
				}
				l.LogInfo(val);
			}
			else if (!flag && _active)
			{
				_active = false;
			}
		}

		private static void RefreshFromServer()
		{
			if (!_active || Time.time < _nextRefresh)
			{
				return;
			}
			_nextRefresh = Time.time + 1f;
			DateTime dateTime = DateTime.MinValue;
			string path = DataFileFor(_localId);
			try
			{
				if (File.Exists(path))
				{
					dateTime = File.GetLastWriteTimeUtc(path);
				}
			}
			catch
			{
			}
			if (dateTime != _fileStamp)
			{
				_fileStamp = dateTime;
				List<Section> sections = ReadServerSections();
				if (Signature(sections) != _signature)
				{
					Rebuild(sections);
				}
			}
			else if (Enforced.Count == 0)
			{
				Rebuild(ReadServerSections());
			}
			if (_remoteSections.Count == 0 || Time.time - _lastDataTime > 10f)
			{
				ChatSync.Request();
			}
		}

		private static void EnforceTexts()
		{
			if (!_active || Enforced.Count == 0 || Time.time < _nextEnforce)
			{
				return;
			}
			_nextEnforce = Time.time + 0.25f;
			for (int i = 0; i < Enforced.Count; i++)
			{
				(TMP_Text, string) tuple = Enforced[i];
				if (!((Object)(object)tuple.Item1 == (Object)null) && tuple.Item1.text != tuple.Item2)
				{
					tuple.Item1.text = tuple.Item2;
				}
			}
		}

		private static void ResetState()
		{
			_built = false;
			_active = false;
			_nativeTab = false;
			_tabIndex = -1;
			_built = false;
			_root = null;
			_content = null;
			_button = null;
			_buttonLabel = null;
			_buttonRect = null;
			_highlight = null;
			_windowGroup = null;
			_headerTemplate = null;
			_dividerTemplate = null;
			_rowTemplate = null;
			VanillaButtons.Clear();
			Enforced.Clear();
		}

		private static void TryBuild()
		{
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Expected O, but got Unknown
			//IL_015b: 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_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				CleanupExisting(_menu);
			}
			catch
			{
			}
			Il2CppReferenceArray<SimpleStunButton> tabButtons = _menu.TabButtons;
			Il2CppReferenceArray<RectTransform> tabs = _menu.Tabs;
			if (tabButtons == null || ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length == 0 || tabs == null || ((Il2CppArrayBase<RectTransform>)(object)tabs).Length == 0)
			{
				return;
			}
			int num = ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length - 1;
			SimpleStunButton val = ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[num];
			Transform parent = ((Component)val).transform.parent;
			int num2 = 0;
			try
			{
				num2 = Mathf.Clamp(_menu.CurrentTab, 0, num);
			}
			catch
			{
			}
			Image component = ((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[num2]).GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				_selectedSprite = component.sprite;
			}
			for (int i = 0; i < ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length; i++)
			{
				Image val2 = (((Object)(object)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[i] == (Object)null) ? null : ((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[i]).GetComponent<Image>());
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.sprite == (Object)null) && (Object)(object)_selectedSprite != (Object)null && (Object)(object)val2.sprite != (Object)(object)_selectedSprite)
				{
					_normalSprite = val2.sprite;
					break;
				}
			}
			if ((Object)(object)_selectedSprite == (Object)null)
			{
				_selectedSprite = _normalSprite;
			}
			if ((Object)(object)_normalSprite == (Object)null)
			{
				_normalSprite = _selectedSprite;
			}
			TMP_Text componentInChildren = ((Component)val).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				_selectedColor = ((Graphic)componentInChildren).color;
			}
			TMP_Text componentInChildren2 = ((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[0]).GetComponentInChildren<TMP_Text>(true);
			_normalColor = (((Object)(object)componentInChildren2 != (Object)null && ((Graphic)componentInChildren2).color != _selectedColor) ? ((Graphic)componentInChildren2).color : _selectedColor);
			Color? val3 = FindGreenValue(((Il2CppArrayBase<RectTransform>)(object)tabs)[num]);
			if (val3.HasValue)
			{
				_green = val3.Value;
			}
			GameObject obj3 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent);
			((Object)obj3).name = "BloodTabButton";
			obj3.SetActive(true);
			_button = obj3.GetComponent<SimpleStunButton>();
			_buttonRect = obj3.GetComponent<RectTransform>();
			_buttonLabel = obj3.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)_buttonLabel != (Object)null)
			{
				_buttonLabel.text = Localization.TabTitle;
				_buttonLabel.enableWordWrapping = false;
				_buttonLabel.enableAutoSizing = true;
				_buttonLabel.fontSizeMin = 9f;
				_buttonLabel.fontSizeMax = 20f;
				_buttonLabel.overflowMode = (TextOverflowModes)0;
				((Graphic)_buttonLabel).color = _normalColor;
			}
			obj3.transform.SetAsLastSibling();
			_highlight = CreateHighlight(obj3.transform);
			try
			{
				((UnityEventBase)_button.onClick).RemoveAllListeners();
			}
			catch
			{
			}
			for (int j = 0; j < ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length; j++)
			{
				VanillaButtons.Add(((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[j]);
			}
			ShrinkTabStrip(parent, tabButtons);
			GameObject gameObject = ((Component)((Il2CppArrayBase<RectTransform>)(object)tabs)[num]).gameObject;
			_root = Object.Instantiate<GameObject>(gameObject, gameObject.transform.parent);
			((Object)_root).name = "BloodTab";
			_root.SetActive(false);
			_windowGroup = (((Object)(object)gameObject.transform.parent == (Object)null) ? null : ((Component)gameObject.transform.parent).GetComponent<CanvasGroup>());
			AddBackground(_root.transform);
			_content = FindDeep(_root.transform, "AttributesTabContent");
			if ((Object)(object)_content == (Object)null)
			{
				Plugin.L.LogWarning((object)"[BuffsTab] AttributesTabContent not found - the tab clone was not built");
				return;
			}
			ClearContent();
			RegisterAsNativeTab(tabButtons, tabs);
			_built = true;
			ManualLogSource l = Plugin.L;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(40, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[BuffsTab] tab built (buttons=");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", native=");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<bool>(_nativeTab);
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(")");
			}
			l.LogInfo(val4);
			Rebuild(ReadServerSections());
		}

		private static void RegisterAsNativeTab(Il2CppReferenceArray<SimpleStunButton> buttons, Il2CppReferenceArray<RectTransform> tabs)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			try
			{
				int num = (_tabIndex = ((Il2CppArrayBase<SimpleStunButton>)(object)buttons).Length);
				Il2CppReferenceArray<SimpleStunButton> val = new Il2CppReferenceArray<SimpleStunButton>((long)(num + 1));
				for (int i = 0; i < num; i++)
				{
					((Il2CppArrayBase<SimpleStunButton>)(object)val)[i] = ((Il2CppArrayBase<SimpleStunButton>)(object)buttons)[i];
				}
				((Il2CppArrayBase<SimpleStunButton>)(object)val)[num] = _button;
				Il2CppReferenceArray<RectTransform> val2 = new Il2CppReferenceArray<RectTransform>((long)(num + 1));
				for (int j = 0; j < ((Il2CppArrayBase<RectTransform>)(object)tabs).Length; j++)
				{
					((Il2CppArrayBase<RectTransform>)(object)val2)[j] = ((Il2CppArrayBase<RectTransform>)(object)tabs)[j];
				}
				((Il2CppArrayBase<RectTransform>)(object)val2)[num] = _root.GetComponent<RectTransform>();
				_menu.TabButtons = val;
				_menu.Tabs = val2;
				_nativeTab = true;
				ManualLogSource l = Plugin.L;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(58, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[BuffsTab] tab registered with the game as index ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(_tabIndex);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" (total ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num + 1);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(")");
				}
				l.LogInfo(val3);
			}
			catch (Exception ex)
			{
				_nativeTab = false;
				_tabIndex = -1;
				_built = false;
				Plugin.L.LogWarning((object)("[BuffsTab] native registration failed, falling back to overlay: " + ex.Message));
			}
		}

		private static void ShrinkTabStrip(Transform strip, Il2CppReferenceArray<SimpleStunButton> tabButtons)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)strip == (Object)null || tabButtons == null)
			{
				return;
			}
			int num = ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length + 1;
			RectTransform component = ((Component)strip).GetComponent<RectTransform>();
			HorizontalLayoutGroup component2 = ((Component)strip).GetComponent<HorizontalLayoutGroup>();
			float num2 = (((Object)(object)component2 != (Object)null) ? ((HorizontalOrVerticalLayoutGroup)component2).spacing : 0f);
			float num3;
			if (!((Object)(object)component != (Object)null))
			{
				num3 = 110f;
			}
			else
			{
				Rect rect = component.rect;
				num3 = (((Rect)(ref rect)).width - num2 * (float)(num - 1)) / (float)num;
			}
			float num4 = num3;
			if (num4 < 84f)
			{
				num4 = 84f;
			}
			List<Transform> list = new List<Transform>();
			for (int i = 0; i < ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length; i++)
			{
				if ((Object)(object)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[i] != (Object)null)
				{
					list.Add(((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[i]).transform);
				}
			}
			if ((Object)(object)_button != (Object)null)
			{
				list.Add(((Component)_button).transform);
			}
			foreach (Transform item in list)
			{
				if (!((Object)(object)item == (Object)null))
				{
					LayoutElement val = ((Component)item).GetComponent<LayoutElement>();
					if ((Object)(object)val == (Object)null)
					{
						val = ((Component)item).gameObject.AddComponent<LayoutElement>();
					}
					val.preferredWidth = num4;
					val.flexibleWidth = 0f;
					TMP_Text componentInChildren = ((Component)item).GetComponentInChildren<TMP_Text>(true);
					if (!((Object)(object)componentInChildren == (Object)null))
					{
						componentInChildren.enableAutoSizing = true;
						componentInChildren.fontSizeMin = 9f;
						componentInChildren.fontSizeMax = 20f;
						componentInChildren.enableWordWrapping = false;
						componentInChildren.overflowMode = (TextOverflowModes)0;
					}
				}
			}
		}

		private static Image CreateHighlight(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002a: 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_004a: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject("BloodTabHighlight");
				val.transform.SetParent(parent, false);
				val.transform.SetAsFirstSibling();
				RectTransform obj = val.AddComponent<RectTransform>();
				obj.anchorMin = Vector2.zero;
				obj.anchorMax = Vector2.one;
				obj.offsetMin = new Vector2(3f, 4f);
				obj.offsetMax = new Vector2(-3f, -3f);
				Image obj2 = val.AddComponent<Image>();
				obj2.sprite = null;
				obj2.type = (Type)0;
				((Graphic)obj2).color = new Color(0.62f, 0.1f, 0.12f, 1f);
				((Graphic)obj2).raycastTarget = false;
				val.SetActive(false);
				return obj2;
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] highlight: " + ex.Message));
				return null;
			}
		}

		private static void AddBackground(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject("BloodTabBackground");
				val.transform.SetParent(parent, false);
				val.transform.SetAsFirstSibling();
				RectTransform obj = val.AddComponent<RectTransform>();
				obj.anchorMin = Vector2.zero;
				obj.anchorMax = Vector2.one;
				obj.offsetMin = Vector2.zero;
				obj.offsetMax = Vector2.zero;
				Image obj2 = val.AddComponent<Image>();
				obj2.sprite = null;
				obj2.type = (Type)0;
				((Graphic)obj2).color = new Color(0.043f, 0.043f, 0.055f, 1f);
				((Graphic)obj2).raycastTarget = false;
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] background: " + ex.Message));
			}
		}

		private static void PollClicks()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Mouse current = Mouse.current;
				if (current == null || !current.leftButton.wasPressedThisFrame)
				{
					return;
				}
				int frameCount = Time.frameCount;
				if (frameCount == _lastClickFrame)
				{
					return;
				}
				Vector2 val = ((InputControl<Vector2>)(object)((Pointer)current).position).ReadValue();
				Camera val2 = null;
				Canvas val3 = (((Object)(object)_button != (Object)null) ? ((Component)_button).GetComponentInParent<Canvas>() : null);
				if ((Object)(object)val3 != (Object)null && (int)val3.renderMode != 0)
				{
					val2 = val3.worldCamera;
				}
				if ((Object)(object)_buttonRect != (Object)null && RectTransformUtility.RectangleContainsScreenPoint(_buttonRect, val, val2))
				{
					_lastClickFrame = frameCount;
					if (_nativeTab)
					{
						try
						{
							_menu.CurrentTab = _tabIndex;
							return;
						}
						catch (Exception ex)
						{
							Plugin.L.LogWarning((object)("[BuffsTab] native switch failed: " + ex.Message));
							_nativeTab = false;
							return;
						}
					}
					if (!_active)
					{
						ActivateOverlay();
					}
					return;
				}
				for (int i = 0; i < VanillaButtons.Count; i++)
				{
					SimpleStunButton val4 = VanillaButtons[i];
					if ((Object)(object)val4 == (Object)null)
					{
						continue;
					}
					RectTransform component = ((Component)val4).GetComponent<RectTransform>();
					if (!((Object)(object)component == (Object)null) && RectTransformUtility.RectangleContainsScreenPoint(component, val, val2))
					{
						_lastClickFrame = frameCount;
						if (!_nativeTab && _active)
						{
							DeactivateOverlay();
						}
						break;
					}
				}
			}
			catch (Exception ex2)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] clicks: " + ex2.Message));
			}
		}

		private static void ActivateOverlay()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_built && !((Object)(object)_root == (Object)null))
				{
					Rebuild(ReadServerSections());
					_root.SetActive(true);
					_root.transform.SetAsLastSibling();
					_active = true;
					_layoutFrames = 3;
					if ((Object)(object)_highlight != (Object)null)
					{
						((Component)_highlight).gameObject.SetActive(true);
					}
					if ((Object)(object)_buttonLabel != (Object)null)
					{
						((Graphic)_buttonLabel).color = Color.white;
					}
					LogLayout();
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] activate: " + ex.Message));
			}
		}

		private static void DeactivateOverlay()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_root != (Object)null)
				{
					_root.SetActive(false);
				}
				_active = false;
				if ((Object)(object)_highlight != (Object)null)
				{
					((Component)_highlight).gameObject.SetActive(false);
				}
				if ((Object)(object)_buttonLabel != (Object)null)
				{
					((Graphic)_buttonLabel).color = _normalColor;
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] deactivate: " + ex.Message));
			}
		}

		private static void WarmUpTemplates()
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Expected O, but got Unknown
			try
			{
				if (_warmStage == 2 || _active)
				{
					return;
				}
				if (_warmStage == 0)
				{
					if ((Object)(object)FindRowTemplate() != (Object)null)
					{
						_warmStage = 2;
					}
					else if (Time.frameCount >= _warmRetryAt)
					{
						_warmPrevTab = 0;
						try
						{
							_warmPrevTab = _menu.CurrentTab;
						}
						catch
						{
						}
						try
						{
							_menu.CurrentTab = 3;
						}
						catch
						{
							_warmStage = 2;
							return;
						}
						_warmFrame = Time.frameCount;
						_warmStage = 1;
					}
				}
				else if (_warmStage == 1 && Time.frameCount > _warmFrame + 4)
				{
					try
					{
						_menu.CurrentTab = _warmPrevTab;
					}
					catch
					{
					}
					_warmStage = 2;
					_rowTemplate = FindRowTemplate();
					_headerTemplate = FindTemplate("AttributesHeader");
					_dividerTemplate = FindTemplate("HDiv");
					ManualLogSource l = Plugin.L;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BuffsTab] templates warmed up: row=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)(object)_rowTemplate == (Object)null) ? "null" : ((Object)_rowTemplate).name);
					}
					l.LogInfo(val);
					if ((Object)(object)_rowTemplate == (Object)null)
					{
						_warmStage = 0;
						_warmRetryAt = Time.frameCount + 90;
					}
				}
			}
			catch (Exception ex)
			{
				_warmStage = 2;
				Plugin.L.LogWarning((object)("[BuffsTab] warmup: " + ex.Message));
			}
		}

		private static GameObject FindRowTemplate()
		{
			List<CharacterAttributeSection> attributeSections = _menu.AttributeSections;
			if (attributeSections == null)
			{
				return null;
			}
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < attributeSections.Count; j++)
				{
					CharacterAttributeSection val = attributeSections[j];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Transform val2 = FindDeep(((Component)val).transform, "AttributesContainer");
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					for (int k = 0; k < val2.childCount; k++)
					{
						Transform child = val2.GetChild(k);
						if (((Component)child).gameObject.activeSelf)
						{
							bool flag = ((Object)child).name.EndsWith("(Clone)");
							if ((i != 0 || (flag && HasFilledText(child))) && (i != 1 || flag))
							{
								return ((Component)child).gameObject;
							}
						}
					}
				}
			}
			return null;
		}

		private static bool HasFilledText(Transform row)
		{
			foreach (TMP_Text componentsInChild in ((Component)row).GetComponentsInChildren<TMP_Text>(true))
			{
				if (!((Object)(object)componentsInChild == (Object)null))
				{
					string text = componentsInChild.text;
					if (!string.IsNullOrEmpty(text) && !text.StartsWith("{") && !(text == "Weapon Level"))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static GameObject FindTemplate(string name)
		{
			List<CharacterAttributeSection> attributeSections = _menu.AttributeSections;
			if (attributeSections != null)
			{
				for (int i = 0; i < attributeSections.Count; i++)
				{
					if (!((Object)(object)attributeSections[i] == (Object)null))
					{
						Transform val = FindDeep(((Component)attributeSections[i]).transform, name);
						if ((Object)(object)val != (Object)null)
						{
							return ((Component)val).gameObject;
						}
					}
				}
			}
			Il2CppReferenceArray<RectTransform> tabs = _menu.Tabs;
			if (tabs == null)
			{
				return null;
			}
			for (int j = 0; j < ((Il2CppArrayBase<RectTransform>)(object)tabs).Length; j++)
			{
				if (!((Object)(object)((Il2CppArrayBase<RectTransform>)(object)tabs)[j] == (Object)null))
				{
					Transform val2 = FindDeep((Transform)(object)((Il2CppArrayBase<RectTransform>)(object)tabs)[j], name);
					if ((Object)(object)val2 != (Object)null)
					{
						return ((Component)val2).gameObject;
					}
				}
			}
			return null;
		}

		private static string DataFileFor(ulong id)
		{
			string path = Plugin.SyncDirectory();
			if (id != 0L)
			{
				string text = Path.Combine(path, $"{"universalcooldown_buffs"}_{id}.txt");
				if (File.Exists(text))
				{
					return text;
				}
			}
			return Path.Combine(path, "universalcooldown_buffs.txt");
		}

		private static void TryResolveLocalId(World world)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			if (Time.time < _nextIdTry)
			{
				return;
			}
			_nextIdTry = Time.time + 5f;
			try
			{
				EntityManager entityManager = world.EntityManager;
				EntityQuery val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<LocalUser>() });
				NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
				try
				{
					bool flag = default(bool);
					for (int i = 0; i < val2.Length; i++)
					{
						Entity val3 = val2[i];
						if (!((EntityManager)(ref entityManager)).HasComponent<User>(val3))
						{
							continue;
						}
						User componentData = ((EntityManager)(ref entityManager)).GetComponentData<User>(val3);
						if (componentData.PlatformId != 0L)
						{
							_localId = componentData.PlatformId;
							_fileStamp = DateTime.MinValue;
							ManualLogSource l = Plugin.L;
							BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(34, 0, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[BuffsTab] local steam id resolved");
							}
							l.LogInfo(val4);
							break;
						}
					}
				}
				finally
				{
					val2.Dispose();
					((EntityQuery)(ref val)).Dispose();
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] local id: " + ex.Message));
			}
		}

		private static void CleanupExisting(InventorySubMenu menu)
		{
			if ((Object)(object)menu == (Object)null)
			{
				return;
			}
			Il2CppReferenceArray<SimpleStunButton> tabButtons = menu.TabButtons;
			Il2CppReferenceArray<RectTransform> tabs = menu.Tabs;
			if (tabs != null)
			{
				for (int i = 0; i < ((Il2CppArrayBase<RectTransform>)(object)tabs).Length; i++)
				{
					RectTransform val = ((Il2CppArrayBase<RectTransform>)(object)tabs)[i];
					if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && !(((Object)((Component)val).gameObject).name != "BloodTab"))
					{
						((Component)val).gameObject.SetActive(false);
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
				}
			}
			Transform val2 = null;
			if (tabButtons != null)
			{
				for (int j = 0; j < ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length; j++)
				{
					if (!((Object)(object)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[j] == (Object)null))
					{
						val2 = ((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[j]).transform.parent;
						break;
					}
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				for (int num = val2.childCount - 1; num >= 0; num--)
				{
					Transform child = val2.GetChild(num);
					if (!((Object)(object)child == (Object)null) && !(((Object)child).name != "BloodTabButton"))
					{
						((Component)child).gameObject.SetActive(false);
						Object.Destroy((Object)(object)((Component)child).gameObject);
					}
				}
			}
			menu.TabButtons = WithoutOurButtons(tabButtons);
			menu.Tabs = WithoutOurTabs(tabs);
		}

		private static Il2CppReferenceArray<SimpleStunButton> WithoutOurButtons(Il2CppReferenceArray<SimpleStunButton> buttons)
		{
			if (buttons == null)
			{
				return null;
			}
			int num = 0;
			for (int i = 0; i < ((Il2CppArrayBase<SimpleStunButton>)(object)buttons).Length; i++)
			{
				if ((Object)(object)((Il2CppArrayBase<SimpleStunButton>)(object)buttons)[i] != (Object)null && ((Object)((Component)((Il2CppArrayBase<SimpleStunButton>)(object)buttons)[i]).gameObject).name != "BloodTabButton")
				{
					num++;
				}
			}
			Il2CppReferenceArray<SimpleStunButton> val = new Il2CppReferenceArray<SimpleStunButton>((long)num);
			int num2 = 0;
			for (int j = 0; j < ((Il2CppArrayBase<SimpleStunButton>)(object)buttons).Length; j++)
			{
				if (!((Object)(object)((Il2CppArrayBase<SimpleStunButton>)(object)buttons)[j] == (Object)null) && !(((Object)((Component)((Il2CppArrayBase<SimpleStunButton>)(object)buttons)[j]).gameObject).name == "BloodTabButton"))
				{
					((Il2CppArrayBase<SimpleStunButton>)(object)val)[num2++] = ((Il2CppArrayBase<SimpleStunButton>)(object)buttons)[j];
				}
			}
			return val;
		}

		private static Il2CppReferenceArray<RectTransform> WithoutOurTabs(Il2CppReferenceArray<RectTransform> tabs)
		{
			if (tabs == null)
			{
				return null;
			}
			int num = 0;
			for (int i = 0; i < ((Il2CppArrayBase<RectTransform>)(object)tabs).Length; i++)
			{
				if ((Object)(object)((Il2CppArrayBase<RectTransform>)(object)tabs)[i] != (Object)null && ((Object)((Component)((Il2CppArrayBase<RectTransform>)(object)tabs)[i]).gameObject).name != "BloodTab")
				{
					num++;
				}
			}
			Il2CppReferenceArray<RectTransform> val = new Il2CppReferenceArray<RectTransform>((long)num);
			int num2 = 0;
			for (int j = 0; j < ((Il2CppArrayBase<RectTransform>)(object)tabs).Length; j++)
			{
				if (!((Object)(object)((Il2CppArrayBase<RectTransform>)(object)tabs)[j] == (Object)null) && !(((Object)((Component)((Il2CppArrayBase<RectTransform>)(object)tabs)[j]).gameObject).name == "BloodTab"))
				{
					((Il2CppArrayBase<RectTransform>)(object)val)[num2++] = ((Il2CppArrayBase<RectTransform>)(object)tabs)[j];
				}
			}
			return val;
		}

		internal static void OnRemotePayload(string payload)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			try
			{
				List<Section> list = ParseSections(payload);
				if (list.Count != 0)
				{
					_remoteSections = list;
					_lastSections = list;
					_lastDataTime = Time.time;
					if (_active)
					{
						Rebuild(list);
					}
					ManualLogSource l = Plugin.L;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(46, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BuffsTab] data received over chat (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" sections)");
					}
					l.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] remote data: " + ex.Message));
			}
		}

		private static List<Section> ReadServerSections()
		{
			List<Section> list = new List<Section>();
			try
			{
				string path = DataFileFor(_localId);
				if (File.Exists(path))
				{
					list = ParseSections(File.ReadAllText(path, Encoding.UTF8));
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] read: " + ex.Message));
			}
			if (list.Count > 0)
			{
				return list;
			}
			return _remoteSections;
		}

		private static List<Section> ParseSections(string text)
		{
			List<Section> list = new List<Section>();
			try
			{
				Section section = null;
				string[] array = (text ?? string.Empty).Split('\n');
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = array[i].TrimEnd();
					if (text2.Length == 0)
					{
						continue;
					}
					string[] array2 = text2.Split('|');
					if (array2[0] == "V")
					{
						continue;
					}
					if (array2[0] == "S")
					{
						section = new Section();
						string text3 = ((array2.Length >= 2) ? array2[1] : string.Empty);
						string arg = ((array2.Length >= 3) ? array2[2] : string.Empty);
						if (text3 == "meta")
						{
							section = null;
							continue;
						}
						if (IsKnownKind(text3))
						{
							section.Kind = text3;
							section.Title = Localization.SectionTitle(text3, arg);
						}
						else if (array2.Length == 2)
						{
							section.Title = array2[1];
						}
						list.Add(section);
					}
					else if (!(array2[0] != "R"))
					{
						if (array2.Length >= 2 && array2[1] == "rates")
						{
							ApplyRates(array2);
						}
						else if (section != null)
						{
							AddRow(section, array2);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] parse: " + ex.Message));
			}
			for (int j = 0; j < list.Count; j++)
			{
				if (list[j].Rows.Count <= 0)
				{
					list[j].Rows.Add(new KeyValuePair<string, string>(Localization.EmptyHint(list[j].Kind), "—"));
				}
			}
			return list;
		}

		private static bool IsKnownKind(string kind)
		{
			switch (kind)
			{
			default:
				return kind == "weapon";
			case "general":
			case "class":
			case "blood":
				return true;
			}
		}

		private static void ApplyRates(string[] parts)
		{
			if (parts.Length >= 5)
			{
				if (float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					Plugin.ServerSpell = result;
				}
				if (float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result))
				{
					Plugin.ServerWeapon = result;
				}
				if (float.TryParse(parts[4], NumberStyles.Float, CultureInfo.InvariantCulture, out result))
				{
					Plugin.ServerUltimate = result;
				}
			}
		}

		private static void AddRow(Section section, string[] parts)
		{
			if (parts.Length < 2)
			{
				return;
			}
			string text = parts[1];
			if (text == "shroud" && parts.Length == 2)
			{
				section.Rows.Add(new KeyValuePair<string, string>(Localization.Shroud, Localization.ShroudOn));
			}
			else if (text == "prestige" && parts.Length >= 4)
			{
				if (int.TryParse(parts[3], out var result))
				{
					section.Rows.Add(new KeyValuePair<string, string>(Localization.PrestigeName(parts[2]), Localization.PrestigeLevel(result)));
				}
			}
			else if (text == "synergy" && parts.Length >= 4)
			{
				if (float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
				{
					section.Rows.Add(new KeyValuePair<string, string>(Localization.Stat(parts[2]), Localization.FormatMultiplier(result2)));
				}
			}
			else if (text == "stat" && parts.Length >= 4)
			{
				if (float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
				{
					section.Rows.Add(new KeyValuePair<string, string>(Localization.Stat(parts[2]), Localization.FormatStat(parts[2], result3)));
				}
			}
			else if (parts.Length >= 3)
			{
				section.Rows.Add(new KeyValuePair<string, string>(parts[1], parts[2]));
			}
		}

		private static string Signature(List<Section> sections)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Section section in sections)
			{
				stringBuilder.Append(section.Title).Append('|');
				foreach (KeyValuePair<string, string> row in section.Rows)
				{
					stringBuilder.Append(row.Key).Append('=').Append(row.Value)
						.Append(';');
				}
				stringBuilder.Append('\n');
			}
			return stringBuilder.ToString();
		}

		private static void ClearContent()
		{
			if (!((Object)(object)_content == (Object)null))
			{
				for (int num = _content.childCount - 1; num >= 0; num--)
				{
					GameObject gameObject = ((Component)_content.GetChild(num)).gameObject;
					gameObject.SetActive(false);
					Object.Destroy((Object)(object)gameObject);
				}
			}
		}

		private static void Rebuild(List<Section> sections)
		{
			if ((Object)(object)_content == (Object)null)
			{
				return;
			}
			ClearContent();
			Enforced.Clear();
			_rowTemplate = (((Object)(object)_rowTemplate != (Object)null) ? _rowTemplate : FindRowTemplate());
			_headerTemplate = (((Object)(object)_headerTemplate != (Object)null) ? _headerTemplate : FindTemplate("AttributesHeader"));
			_dividerTemplate = (((Object)(object)_dividerTemplate != (Object)null) ? _dividerTemplate : FindTemplate("HDiv"));
			if (sections.Count == 0 && _lastSections.Count > 0)
			{
				sections = _lastSections;
			}
			else if (sections.Count > 0)
			{
				_lastSections = sections;
			}
			if (sections.Count == 0)
			{
				sections = new List<Section>
				{
					new Section
					{
						Kind = "",
						Title = "",
						Rows = 
						{
							new KeyValuePair<string, string>(Localization.Loading, "")
						}
					}
				};
			}
			foreach (Section section in sections)
			{
				AddSection(section);
			}
			_signature = Signature(sections);
			RebuildLayout();
		}

		private static void AddSection(Section section)
		{
			bool flag = section.Rows.Count == 1 && string.IsNullOrEmpty(section.Rows[0].Value);
			Transform container;
			GameObject val = BuildSection(section.Title, out container, flag);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (flag)
			{
				AddPlainText(val.transform, section.Rows[0].Key);
				return;
			}
			foreach (KeyValuePair<string, string> row in section.Rows)
			{
				AddRowView(container, row.Key, row.Value);
			}
		}

		private static void AddPlainText(Transform parent, string text)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0037: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject val = new GameObject("BuffsPlainText");
				val.transform.SetParent(parent, false);
				val.AddComponent<RectTransform>();
				TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
				((TMP_Text)val2).text = text;
				((TMP_Text)val2).fontSize = 18f;
				((Graphic)val2).color = TextColor;
				((TMP_Text)val2).alignment = (TextAlignmentOptions)513;
				((TMP_Text)val2).enableWordWrapping = true;
				((TMP_Text)val2).overflowMode = (TextOverflowModes)0;
				Enforced.Add(((TMP_Text)(object)val2, text));
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] plain text: " + ex.Message));
			}
		}

		private static GameObject BuildSection(string title, out Transform container, bool withoutGrid = false)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0030: 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)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_008a: 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_009f: Expected O, but got Unknown
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			container = null;
			GameObject val = new GameObject("BuffsSection");
			val.transform.SetParent(_content, false);
			RectTransform obj = val.AddComponent<RectTransform>();
			obj.anchorMin = new Vector2(0f, 1f);
			obj.anchorMax = new Vector2(1f, 1f);
			obj.pivot = new Vector2(0.5f, 1f);
			VerticalLayoutGroup obj2 = val.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 6f;
			((LayoutGroup)obj2).padding = new RectOffset
			{
				left = 12,
				right = 12,
				top = 10,
				bottom = 10
			};
			((LayoutGroup)obj2).childAlignment = (TextAnchor)1;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			if ((Object)(object)_headerTemplate != (Object)null && !string.IsNullOrEmpty(title))
			{
				GameObject val2 = Object.Instantiate<GameObject>(_headerTemplate, val.transform);
				val2.SetActive(true);
				((Object)val2).name = "BuffsHeader";
				StripInteractive(val2);
				TMP_Text val3 = val2.GetComponent<TMP_Text>();
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = val2.GetComponentInChildren<TMP_Text>(true);
				}
				if ((Object)(object)val3 != (Object)null)
				{
					val3.text = title;
					val3.enableWordWrapping = false;
					Enforced.Add((val3, title));
				}
			}
			if ((Object)(object)_dividerTemplate != (Object)null)
			{
				GameObject obj3 = Object.Instantiate<GameObject>(_dividerTemplate, val.transform);
				obj3.SetActive(true);
				((Object)obj3).name = "BuffsDivider";
			}
			if (withoutGrid)
			{
				return val;
			}
			GameObject val4 = new GameObject("BuffsGrid");
			val4.transform.SetParent(val.transform, false);
			val4.AddComponent<RectTransform>();
			GridLayoutGroup obj4 = val4.AddComponent<GridLayoutGroup>();
			obj4.cellSize = new Vector2(280f, 40f);
			obj4.spacing = new Vector2(10f, 4f);
			obj4.constraint = (Constraint)1;
			obj4.constraintCount = 2;
			((LayoutGroup)obj4).childAlignment = (TextAnchor)3;
			val4.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
			container = val4.transform;
			return val;
		}

		private static void AddRowView(Transform container, string name, string value)
		{
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (((Object)(object)_rowTemplate != (Object)null) ? _rowTemplate : FindRowTemplate());
			if ((Object)(object)val == (Object)null || (Object)(object)container == (Object)null)
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, container);
			((Object)val2).name = "BuffRow";
			val2.SetActive(true);
			StripInteractive(val2);
			List<TMP_Text> list = new List<TMP_Text>();
			foreach (TMP_Text componentsInChild in val2.GetComponentsInChildren<TMP_Text>(true))
			{
				if ((Object)(object)componentsInChild != (Object)null)
				{
					list.Add(componentsInChild);
				}
			}
			TMP_Text val3 = null;
			TMP_Text val4 = null;
			for (int i = 0; i < list.Count; i++)
			{
				string name2 = ((Object)((Component)list[i]).gameObject).name;
				if ((Object)(object)val3 == (Object)null && name2.StartsWith("AttributeName"))
				{
					val3 = list[i];
				}
				else if ((Object)(object)val4 == (Object)null && name2.StartsWith("AttributeValue"))
				{
					val4 = list[i];
				}
			}
			if ((Object)(object)val3 == (Object)null && list.Count > 0)
			{
				val3 = list[0];
			}
			if ((Object)(object)val4 == (Object)null && list.Count > 1)
			{
				val4 = list[1];
			}
			for (int j = 0; j < list.Count; j++)
			{
				if (!((Object)(object)list[j] == (Object)(object)val3) && !((Object)(object)list[j] == (Object)(object)val4))
				{
					Object.Destroy((Object)(object)((Component)list[j]).gameObject);
				}
			}
			LayoutRow(val3, val4);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.text = name;
				((Graphic)val3).color = TextColor;
				val3.enableWordWrapping = false;
				val3.enableAutoSizing = true;
				val3.fontSizeMin = 9f;
				val3.fontSizeMax = 15f;
				val3.overflowMode = (TextOverflowModes)1;
				val3.alignment = (TextAlignmentOptions)513;
				Enforced.Add((val3, name));
			}
			if ((Object)(object)val4 != (Object)null)
			{
				val4.text = value;
				((Graphic)val4).color = (value.StartsWith("+") ? _green : TextColor);
				val4.enableWordWrapping = false;
				val4.enableAutoSizing = true;
				val4.fontSizeMin = 10f;
				val4.fontSizeMax = 16f;
				val4.alignment = (TextAlignmentOptions)516;
				Enforced.Add((val4, value));
			}
			Transform val5 = FindDeep(val2.transform, "ProgressBar");
			if ((Object)(object)val5 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val5).gameObject);
			}
			Transform val6 = FindDeep(val2.transform, "BorderFocus");
			if ((Object)(object)val6 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val6).gameObject);
			}
		}

		private static void LayoutRow(TMP_Text nameText, TMP_Text valueText)
		{
			try
			{
				if ((Object)(object)nameText != (Object)null && (Object)(object)nameText.transform.parent != (Object)null)
				{
					HorizontalLayoutGroup component = ((Component)nameText.transform.parent).GetComponent<HorizontalLayoutGroup>();
					if ((Object)(object)component != (Object)null)
					{
						((HorizontalOrVerticalLayoutGroup)component).childControlWidth = true;
						((HorizontalOrVerticalLayoutGroup)component).childControlHeight = true;
						((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = false;
						((LayoutGroup)component).childAlignment = (TextAnchor)3;
						((HorizontalOrVerticalLayoutGroup)component).spacing = 4f;
					}
				}
				ApplyLayout(nameText, 1f, -1f, 40f);
				ApplyLayout(valueText, 0f, 72f, -1f);
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] row layout: " + ex.Message));
			}
		}

		private static void ApplyLayout(TMP_Text text, float flexible, float preferred, float min)
		{
			if (!((Object)(object)text == (Object)null))
			{
				LayoutElement val = ((Component)text).GetComponent<LayoutElement>();
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)text).gameObject.AddComponent<LayoutElement>();
				}
				val.flexibleWidth = flexible;
				if (preferred > 0f)
				{
					val.preferredWidth = preferred;
				}
				if (min > 0f)
				{
					val.minWidth = min;
				}
			}
		}

		private static void StripInteractive(GameObject go)
		{
			try
			{
				foreach (Component componentsInChild in go.GetComponentsInChildren<Component>(true))
				{
					if (!((Object)(object)componentsInChild == (Object)null))
					{
						switch (((MemberInfo)((Object)componentsInChild).GetIl2CppType()).Name)
						{
						case "CharacterAttributeEntry":
						case "SimpleStunButton":
						case "Tooltip":
						case "LocalizedText":
							Object.Destroy((Object)(object)componentsInChild);
							break;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BuffsTab] strip: " + ex.Message));
			}
		}

		private static void RebuildLayout()
		{
			try
			{
				Transform content = _content;
				RectTransform val = (RectTransform)(object)((content is RectTransform) ? content : null);
				if (!((Object)(object)val == (Object)null))
				{
					LayoutRebuilder.ForceRebuildLayoutImmediate(val);
					if ((Object)(object)((Transform)val).parent != (Object)null)
					{
						Transform parent = ((Transform)val).parent;
						LayoutRebuilder.MarkLayoutForRebuild((RectTransform)(object)((parent is RectTransform) ? parent : null));
					}
				}
			}
			catch
			{
			}
		}

		private static void LogLayout()
		{
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_content == (Object)null)
				{
					return;
				}
				StringBuilder stringBuilder = new StringBuilder("[BuffsTab] layout:");
				Rect rect;
				StringBuilder stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler;
				for (int i = 0; i < _content.childCount; i++)
				{
					Transform child = _content.GetChild(i);
					if (!((Object)(object)child == (Object)null) && ((Component)child).gameObject.activeSelf)
					{
						RectTransform component = ((Component)child).GetComponent<RectTransform>();
						int value = 0;
						Transform val = FindDeep(child, "BuffsGrid");
						if ((Object)(object)val != (Object)null)
						{
							value = val.childCount;
						}
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder3 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(10, 3, stringBuilder2);
						handler.AppendLiteral(" [");
						float value2;
						if (!((Object)(object)component != (Object)null))
						{
							value2 = -1f;
						}
						else
						{
							rect = component.rect;
							value2 = ((Rect)(ref rect)).width;
						}
						handler.AppendFormatted(value2, "0");
						handler.AppendLiteral("x");
						float value3;
						if (!((Object)(object)component != (Object)null))
						{
							value3 = -1f;
						}
						else
						{
							rect = component.rect;
							value3 = ((Rect)(ref rect)).height;
						}
						handler.AppendFormatted(value3, "0");
						handler.AppendLiteral(" rows=");
						handler.AppendFormatted(value);
						handler.AppendLiteral("]");
						stringBuilder3.Append(ref handler);
					}
				}
				stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder4 = stringBuilder2;
				handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder2);
				handler.AppendLiteral(" tab=");
				float value4;
				if (!((Object)(object)_buttonRect != (Object)null))
				{
					value4 = -1f;
				}
				else
				{
					rect = _buttonRect.rect;
					value4 = ((Rect)(ref rect)).width;
				}
				handler.AppendFormatted(value4, "0");
				handler.AppendLiteral("px");
				stringBuilder4.Append(ref handler);
				Plugin.L.LogInfo((object)stringBuilder.ToString());
			}
			catch
			{
			}
		}

		private static Color? FindGreenValue(RectTransform tab)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)tab == (Object)null)
				{
					return null;
				}
				foreach (TMP_Text componentsInChild in ((Component)tab).GetComponentsInChildren<TMP_Text>(false))
				{
					if ((Object)(object)componentsInChild == (Object)null)
					{
						continue;
					}
					string text = componentsInChild.text;
					if (!string.IsNullOrEmpty(text) && text.Contains("+"))
					{
						Color color = ((Graphic)componentsInChild).color;
						if (color.g > color.r && color.g > color.b)
						{
							return color;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private static Transform FindDeep(Transform root, string name)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			if (((Object)root).name == name)
			{
				return root;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform val = FindDeep(root.GetChild(i), name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}
	}
	internal static class ChatSync
	{
		private const string ProtocolPrefix = "UCUI|";

		private const string RequestCommand = ".ucui d";

		private static World _world;

		private static Entity _localUser;

		private static Entity _localCharacter;

		private static bool _resolved;

		private static float _nextRequest;

		private static readonly List<string> Parts = new List<string>();

		private static int _expected;

		private static int _received;

		private static float _nextAuto;

		internal static void Install(Harmony harmony)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("ProjectM.UI.ClientChatSystem");
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "OnUpdate", (Type[])null, (Type[])null));
				if (methodInfo == null)
				{
					Plugin.L.LogWarning((object)"[ChatSync] ClientChatSystem.OnUpdate not found - chat sync disabled");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ChatSync).GetMethod("OnChatUpdate", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.L.LogInfo((object)"[ChatSync] chat hooked");
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[ChatSync] install: " + ex.Message));
			}
		}

		internal static void ResetSession()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			_resolved = false;
			_localUser = Entity.Null;
			_localCharacter = Entity.Null;
			_world = null;
			_nextAuto = 0f;
			_nextRequest = 0f;
			Parts.Clear();
			_expected = 0;
			_received = 0;
		}

		internal static void SetWorld(World world)
		{
			if (_world == null && world != null)
			{
				_world = world;
			}
		}

		internal static void AutoPoll()
		{
			if (_world != null && !(Time.time < _nextAuto))
			{
				int num = 20;
				try
				{
					num = Plugin.PollSeconds.Value;
				}
				catch
				{
				}
				if (num <= 0)
				{
					_nextAuto = float.MaxValue;
					return;
				}
				_nextAuto = Time.time + (float)Mathf.Clamp(num, 5, 300);
				Request();
			}
		}

		internal static void Request()
		{
			if (_world != null && !(Time.time < _nextRequest))
			{
				_nextRequest = Time.time + 8f;
				Send(".ucui d");
			}
		}

		private static void ResolveLocalEntities(EntityManager em)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			if (_resolved)
			{
				return;
			}
			_resolved = true;
			try
			{
				EntityQuery val = ((EntityManager)(ref em)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<LocalUser>() });
				NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
				try
				{
					if (val2.Length > 0)
					{
						_localUser = val2[0];
					}
				}
				finally
				{
					val2.Dispose();
					((EntityQuery)(ref val)).Dispose();
				}
				EntityQuery val3 = ((EntityManager)(ref em)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<LocalCharacter>() });
				NativeArray<Entity> val4 = ((EntityQuery)(ref val3)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
				try
				{
					if (val4.Length > 0)
					{
						_localCharacter = val4[0];
					}
				}
				finally
				{
					val4.Dispose();
					((EntityQuery)(ref val3)).Dispose();
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[ChatSync] local entities: " + ex.Message));
			}
		}

		private static void Send(string text)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				EntityManager entityManager = _world.EntityManager;
				ResolveLocalEntities(entityManager);
				if (!(_localUser == Entity.Null) && !(_localCharacter == Entity.Null))
				{
					ComponentType[] array = (ComponentType[])(object)new ComponentType[4]
					{
						ComponentType.ReadOnly<FromCharacter>(),
						ComponentType.ReadOnly<NetworkEventType>(),
						ComponentType.ReadOnly<SendNetworkEventTag>(),
						ComponentType.ReadOnly<ChatMessageEvent>()
					};
					ChatMessageEvent val = new ChatMessageEvent
					{
						MessageText = FixedString512Bytes.op_Implicit(text),
						MessageType = (ChatMessageType)4,
						ReceiverEntity = ((EntityManager)(ref entityManager)).GetComponentData<NetworkId>(_localUser)
					};
					NetworkEventType val2 = new NetworkEventType
					{
						IsAdminEvent = false,
						EventId = NetworkEvents.EventId_ChatMessageEvent,
						IsDebugEvent = false
					};
					Entity val3 = ((EntityManager)(ref entityManager)).CreateEntity(array);
					((EntityManager)(ref entityManager)).SetComponentData<FromCharacter>(val3, new FromCharacter
					{
						Character = _localCharacter,
						User = _localUser
					});
					((EntityManager)(ref entityManager)).SetComponentData<NetworkEventType>(val3, val2);
					((EntityManager)(ref entityManager)).SetComponentData<ChatMessageEvent>(val3, val);
					Plugin.L.LogInfo((object)"[ChatSync] data requested");
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[ChatSync] send: " + ex.Message));
			}
		}

		private unsafe static void OnChatUpdate()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0037: 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_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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (_world == null || !_world.IsCreated)
				{
					return;
				}
				EntityManager entityManager = _world.EntityManager;
				EntityQuery val = ((EntityManager)(ref entityManager)).CreateEntityQuery((ComponentType[])(object)new ComponentType[1] { ComponentType.ReadOnly<ChatMessageServerEvent>() });
				NativeArray<Entity> val2 = ((EntityQuery)(ref val)).ToEntityArray(AllocatorHandle.op_Implicit((Allocator)2));
				try
				{
					for (int i = 0; i < val2.Length; i++)
					{
						Entity val3 = val2[i];
						if (!((EntityManager)(ref entityManager)).HasComponent<ChatMessageServerEvent>(val3))
						{
							continue;
						}
						ChatMessageServerEvent componentData = ((EntityManager)(ref entityManager)).GetComponentData<ChatMessageServerEvent>(val3);
						string text = ((object)(*(FixedString512Bytes*)(&componentData.MessageText))/*cast due to .constrained prefix*/).ToString();
						if (!string.IsNullOrEmpty(text))
						{
							if (text.StartsWith("UCUI|", StringComparison.Ordinal))
							{
								HandlePart(text);
								((EntityManager)(ref entityManager)).DestroyEntity(val3);
							}
							else if (text.Trim().StartsWith(".ucui d", StringComparison.OrdinalIgnoreCase))
							{
								((EntityManager)(ref entityManager)).DestroyEntity(val3);
							}
						}
					}
				}
				finally
				{
					val2.Dispose();
					((EntityQuery)(ref val)).Dispose();
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[ChatSync] read: " + ex.Message));
			}
		}

		private static void HandlePart(string text)
		{
			try
			{
				string[] array = text.Split(new char[1] { '|' }, 4);
				if (array.Length >= 4 && int.TryParse(array[1], out var result) && int.TryParse(array[2], out var result2) && result2 > 0 && result > 0)
				{
					if (result2 != _expected || result == 1)
					{
						Parts.Clear();
						_expected = result2;
						_received = 0;
					}
					Parts.Add(array[3]);
					_received++;
					if (_received >= _expected)
					{
						string payload = string.Concat(Parts).Replace('~', '\n');
						Parts.Clear();
						_expected = 0;
						_received = 0;
						BuffsTab.OnRemotePayload(payload);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[ChatSync] part: " + ex.Message));
			}
		}
	}
	internal static class Localization
	{
		internal enum Lang
		{
			English,
			Russian
		}

		internal static Lang Current = Lang.English;

		private static readonly Dictionary<string, string> StatEn = new Dictionary<string, string>
		{
			["MaxHealth"] = "Max health",
			["MovementSpeed"] = "Movement speed",
			["PrimaryAttackSpeed"] = "Attack speed",
			["PhysicalLifeLeech"] = "Physical life leech",
			["SpellLifeLeech"] = "Spell life leech",
			["PrimaryLifeLeech"] = "Primary attack leech",
			["PhysicalPower"] = "Physical power",
			["SpellPower"] = "Spell power",
			["PhysicalCritChance"] = "Physical crit chance",
			["PhysicalCritDamage"] = "Physical crit damage",
			["SpellCritChance"] = "Spell crit chance",
			["SpellCritDamage"] = "Spell crit damage",
			["HealingReceived"] = "Healing received",
			["DamageReduction"] = "Damage reduction",
			["PhysicalResistance"] = "Physical resistance",
			["SpellResistance"] = "Spell resistance",
			["ResourceYield"] = "Resource yield",
			["ReducedBloodDrain"] = "Blood drain reduction",
			["SpellCooldownRecoveryRate"] = "Spell cooldown rate",
			["WeaponCooldownRecoveryRate"] = "Weapon cooldown rate",
			["UltimateCooldownRecoveryRate"] = "Ultimate cooldown rate",
			["MinionDamage"] = "Minion damage",
			["AbilityAttackSpeed"] = "Ability attack speed",
			["CorruptionDamageReduction"] = "Corruption resistance"
		};

		private static readonly Dictionary<string, string> StatRu = new Dictionary<string, string>
		{
			["MaxHealth"] = "Макс. здоровье",
			["MovementSpeed"] = "Скорость движения",
			["PrimaryAttackSpeed"] = "Скорость атаки",
			["PhysicalLifeLeech"] = "Вампиризм (физ.)",
			["SpellLifeLeech"] = "Вампиризм (маг.)",
			["PrimaryLifeLeech"] = "Вампиризм осн. атаки",
			["PhysicalPower"] = "Физическая сила",
			["SpellPower"] = "Сила магии",
			["PhysicalCritChance"] = "Шанс крит. удара (физ.)",
			["PhysicalCritDamage"] = "Крит. урон (физ.)",
			["SpellCritChance"] = "Шанс крит. удара (маг.)",
			["SpellCritDamage"] = "Крит. урон (маг.)",
			["HealingReceived"] = "Исцеление",
			["DamageReduction"] = "Снижение урона",
			["PhysicalResistance"] = "Сопротивление физ.",
			["SpellResistance"] = "Сопротивление маг.",
			["ResourceYield"] = "Добыча",
			["ReducedBloodDrain"] = "Расход крови",
			["SpellCooldownRecoveryRate"] = "КД заклинаний",
			["WeaponCooldownRecoveryRate"] = "КД оружия",
			["UltimateCooldownRecoveryRate"] = "КД ультимейта",
			["MinionDamage"] = "Урон приспешников",
			["AbilityAttackSpeed"] = "Скорость способностей",
			["CorruptionDamageReduction"] = "Сопротивление порче"
		};

		private static readonly Dictionary<string, string> ClassEn = new Dictionary<string, string>
		{
			["BloodKnight"] = "Blood Knight",
			["DemonHunter"] = "Demon Hunter",
			["VampireLord"] = "Vampire Lord",
			["ShadowBlade"] = "Shadow Blade",
			["ArcaneSorcerer"] = "Arcane Sorcerer",
			["DeathMage"] = "Death Mage"
		};

		private static readonly Dictionary<string, string> ClassRu = new Dictionary<string, string>
		{
			["BloodKnight"] = "Кровавый рыцарь",
			["DemonHunter"] = "Охотник на демонов",
			["VampireLord"] = "Владыка вампиров",
			["ShadowBlade"] = "Теневая грань",
			["ArcaneSorcerer"] = "Тайный чародей",
			["DeathMage"] = "Маг смерти"
		};

		private static readonly Dictionary<string, string> BloodEn = new Dictionary<string, string>
		{
			["Worker"] = "Worker",
			["Warrior"] = "Warrior",
			["Scholar"] = "Scholar",
			["Rogue"] = "Rogue",
			["Mutant"] = "Mutant",
			["VBlood"] = "V Blood",
			["None"] = "None",
			["GateBoss"] = "Gate boss",
			["Draculin"] = "Draculin",
			["Immortal"] = "Immortal",
			["Creature"] = "Creature",
			["Brute"] = "Brute",
			["Corruption"] = "Corruption"
		};

		private static readonly Dictionary<string, string> BloodRu = new Dictionary<string, string>
		{
			["Worker"] = "Рабочая",
			["Warrior"] = "Воительская",
			["Scholar"] = "Учёная",
			["Rogue"] = "Разбойничья",
			["Mutant"] = "Мутантская",
			["VBlood"] = "Кровь V",
			["None"] = "Нет",
			["GateBoss"] = "Кровь стража",
			["Draculin"] = "Дракулинская",
			["Immortal"] = "Бессмертная",
			["Creature"] = "Звериная",
			["Brute"] = "Грубая",
			["Corruption"] = "Порченая"
		};

		private static readonly Dictionary<string, string> WeaponEn = new Dictionary<string, string>
		{
			["Sword"] = "Sword",
			["Axe"] = "Axe",
			["Mace"] = "Mace",
			["Spear"] = "Spear",
			["Crossbow"] = "Crossbow",
			["GreatSword"] = "Greatsword",
			["Slashers"] = "Slashers",
			["Pistols"] = "Pistols",
			["Reaper"] = "Reaper",
			["Longbow"] = "Longbow",
			["Whip"] = "Whip",
			["Unarmed"] = "Unarmed",
			["FishingPole"] = "Fishing pole",
			["TwinBlades"] = "Twin blades",
			["Daggers"] = "Daggers",
			["Claws"] = "Claws"
		};

		private static readonly Dictionary<string, string> WeaponRu = new Dictionary<string, string>
		{
			["Sword"] = "Меч",
			["Axe"] = "Топор",
			["Mace"] = "Булава",
			["Spear"] = "Копьё",
			["Crossbow"] = "Арбалет",
			["GreatSword"] = "Двуручный меч",
			["Slashers"] = "Клинки",
			["Pistols"] = "Пистолеты",
			["Reaper"] = "Коса",
			["Longbow"] = "Длинный лук",
			["Whip"] = "Хлыст",
			["Unarmed"] = "Без оружия",
			["FishingPole"] = "Удочка",
			["TwinBlades"] = "Парные клинки",
			["Daggers"] = "Кинжалы",
			["Claws"] = "Когти"
		};

		private static bool Ru => Current == Lang.Russian;

		internal static string TabTitle => "Blood";

		internal static string Loading
		{
			get
			{
				if (!Ru)
				{
					return "Loading server data…";
				}
				return "Данные загружаются…";
			}
		}

		internal static string LoadingHint
		{
			get
			{
				if (!Ru)
				{
					return "a few seconds";
				}
				return "подождите пару секунд";
			}
		}

		internal static string Shroud
		{
			get
			{
				if (!Ru)
				{
					return "Blood shroud";
				}
				return "Плащ крови";
			}
		}

		internal static string ShroudOn
		{
			get
			{
				if (!Ru)
				{
					return "enabled";
				}
				return "включён";
			}
		}

		private static CultureInfo NumberFormat
		{
			get
			{
				if (!Ru)
				{
					return CultureInfo.InvariantCulture;
				}
				return CultureInfo.GetCultureInfo("ru-RU");
			}
		}

		internal static void Init(string configured)
		{
			switch ((configured ?? "auto").Trim().ToLowerInvariant())
			{
			case "en":
			case "english":
				Current = Lang.English;
				return;
			case "ru":
			case "russian":
				Current = Lang.Russian;
				return;
			}
			try
			{
				Current = ((CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ru") ? Lang.Russian : Lang.English);
			}
			catch
			{
				Current = Lang.English;
			}
		}

		internal static string SectionTitle(string kind, string arg)
		{
			switch (kind)
			{
			case "general":
				if (!Ru)
				{
					return "General";
				}
				return "Общие";
			case "class":
				return string.Format(Ru ? "Класс: {0} (синергии)" : "Class: {0} (synergies)", ClassName(arg));
			case "blood":
				return string.Format(Ru ? "Кровь: {0}" : "Blood: {0}", BloodName(arg));
			case "weapon":
				return string.Format(Ru ? "Оружие: {0}" : "Weapon: {0}", WeaponName(arg));
			default:
				return kind;
			}
		}

		internal static string EmptyHint(string kind)
		{
			switch (kind)
			{
			case "general":
				if (!Ru)
				{
					return "No permanent buffs";
				}
				return "Постоянных баффов нет";
			case "class":
				if (!Ru)
				{
					return "No class selected";
				}
				return "Класс не выбран";
			case "blood":
				if (!Ru)
				{
					return "No blood bonuses selected";
				}
				return "Бонусы крови не выбраны";
			case "weapon":
				if (!Ru)
				{
					return "No weapon stats selected";
				}
				return "Опыт оружия не выбран";
			default:
				if (!Ru)
				{
					return "No data";
				}
				return "Нет данных";
			}
		}

		internal static string PrestigeName(string prefab)
		{
			return Humanize(prefab);
		}

		internal static string PrestigeLevel(int level)
		{
			if (Ru)
			{
				return $"ур. {level}";
			}
			return $"lvl {level}";
		}

		internal static bool IsPercent(string key)
		{
			switch (key)
			{
			case "MaxHealth":
			case "PhysicalPower":
			case "SpellPower":
				return false;
			default:
				return true;
			}
		}

		internal static string FormatStat(string key, float value)
		{
			if (IsPercent(key))
			{
				return "+" + (value * 100f).ToString("0.#", NumberFormat) + "%";
			}
			return "+" + value.ToString("0.#", NumberFormat);
		}

		internal static string FormatMultiplier(float value)
		{
			return "×" + value.ToString("0.##", NumberFormat);
		}

		internal static string Stat(string key)
		{
			if (Ru)
			{
				if (!StatRu.TryGetValue(key, out var value))
				{
					return Humanize(key);
				}
				return value;
			}
			if (!StatEn.TryGetValue(key, out var value2))
			{
				return Humanize(key);
			}
			return value2;
		}

		internal static string ClassName(string key)
		{
			if (string.IsNullOrEmpty(key) || key == "none")
			{
				if (!Ru)
				{
					return "none";
				}
				return "не выбран";
			}
			if (!(Ru ? ClassRu : ClassEn).TryGetValue(key, out var value))
			{
				return Humanize(key);
			}
			return value;
		}

		internal static string BloodName(string key)
		{
			if (string.IsNullOrEmpty(key) || key == "none")
			{
				if (!Ru)
				{
					return "none";
				}
				return "нет";
			}
			if (!(Ru ? BloodRu : BloodEn).TryGetValue(key, out var value))
			{
				return Humanize(key);
			}
			return value;
		}

		internal static string WeaponName(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				if (!Ru)
				{
					return "none";
				}
				return "нет";
			}
			if (!(Ru ? WeaponRu : WeaponEn).TryGetValue(key, out var value))
			{
				return Humanize(key);
			}
			return value;
		}

		internal static string Humanize(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return name;
			}
			StringBuilder stringBuilder = new StringBuilder(name.Length + 6);
			for (int i = 0; i < name.Length; i++)
			{
				char c = name[i];
				if (i > 0 && char.IsUpper(c) && !char.IsUpper(name[i - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(c);
			}
			return stringBuilder.ToString();
		}
	}
	internal static class MenuProbe
	{
		internal static InventorySubMenu Menu;

		private static bool _dumpedMenu;

		private static bool _dumpedContent;

		private static int _tick;

		private static readonly StringBuilder Sb = new StringBuilder();

		internal static void Install(Harmony harmony)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("ProjectM.UI.InventorySubMenuMapper");
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "InitializeUI", (Type[])null, (Type[])null));
				if (methodInfo != null)
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(MenuProbe).GetMethod("OnInitializeUI", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.L.LogInfo((object)"[Probe] InitializeUI hooked");
				}
				else
				{
					Plugin.L.LogWarning((object)"[Probe] InventorySubMenuMapper.InitializeUI not found");
				}
				Type type2 = AccessTools.TypeByName("ProjectM.UI.UICanvasSystem");
				MethodInfo methodInfo2 = ((type2 == null) ? null : AccessTools.Method(type2, "UpdateHideIfDisabled", (Type[])null, (Type[])null));
				if (methodInfo2 != null)
				{
					harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(MenuProbe).GetMethod("OnCanvasUpdate", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.L.LogInfo((object)"[Probe] canvas update hooked");
				}
				else
				{
					Plugin.L.LogWarning((object)"[Probe] UICanvasSystem.UpdateHideIfDisabled not found");
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[Probe] install: " + ex));
			}
		}

		private static void OnInitializeUI(InventorySubMenu menu)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			bool flag = (Object)(object)Menu == (Object)null || (Object)(object)menu == (Object)null || ((Il2CppObjectBase)Menu).Pointer != ((Il2CppObjectBase)menu).Pointer;
			if ((Object)(object)Menu == (Object)null)
			{
				ManualLogSource l = Plugin.L;
				bool flag2 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(34, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[Probe] character window found: '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)((Component)menu).gameObject).name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
				}
				l.LogInfo(val);
			}
			else if (flag)
			{
				Plugin.L.LogInfo((object)"[Probe] character window re-created - rebinding");
			}
			Menu = menu;
			if (flag)
			{
				ChatSync.ResetSession();
				BuffsTab.Rebind(menu);
			}
			else
			{
				BuffsTab.Bind(menu);
			}
		}

		private static void OnCanvasUpdate(UICanvasSystem __instance)
		{
			try
			{
				BuffsTab.Tick((__instance == null) ? null : ((ComponentSystemBase)__instance).World);
				if (!((Object)(object)Menu == (Object)null) && ++_tick % 15 == 0 && Plugin.Probe.Value)
				{
					if (!_dumpedMenu)
					{
						_dumpedMenu = true;
						DumpMenu();
					}
					if (((Component)Menu).gameObject.activeInHierarchy && !_dumpedContent)
					{
						_dumpedContent = true;
						DumpContents();
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[Probe] poll: " + ex.Message));
			}
		}

		private static void DumpMenu()
		{
			Sb.Clear();
			Sb.AppendLine("[Probe] ===== MENU =====");
			StringBuilder sb = Sb;
			StringBuilder stringBuilder = sb;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(25, 2, sb);
			handler.AppendLiteral("[Probe] tabButtons=");
			handler.AppendFormatted(((Il2CppArrayBase<SimpleStunButton>)(object)Menu.TabButtons)?.Length);
			handler.AppendLiteral(" tabs=");
			handler.AppendFormatted(((Il2CppArrayBase<RectTransform>)(object)Menu.Tabs)?.Length);
			stringBuilder.AppendLine(ref handler);
			Il2CppReferenceArray<SimpleStunButton> tabButtons = Menu.TabButtons;
			if (tabButtons != null)
			{
				for (int i = 0; i < ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length; i++)
				{
					if (!((Object)(object)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[i] == (Object)null))
					{
						TMP_Text componentInChildren = ((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[i]).GetComponentInChildren<TMP_Text>(true);
						sb = Sb;
						StringBuilder stringBuilder2 = sb;
						handler = new StringBuilder.AppendInterpolatedStringHandler(27, 3, sb);
						handler.AppendLiteral("[Probe]   tab[");
						handler.AppendFormatted(i);
						handler.AppendLiteral("] '");
						handler.AppendFormatted(((Object)((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[i]).gameObject).name);
						handler.AppendLiteral("' label='");
						handler.AppendFormatted(Trunc((componentInChildren != null) ? componentInChildren.text : null));
						handler.AppendLiteral("'");
						stringBuilder2.AppendLine(ref handler);
					}
				}
			}
			Il2CppReferenceArray<RectTransform> tabs = Menu.Tabs;
			if (tabs != null)
			{
				for (int j = 0; j < ((Il2CppArrayBase<RectTransform>)(object)tabs).Length; j++)
				{
					if (!((Object)(object)((Il2CppArrayBase<RectTransform>)(object)tabs)[j] == (Object)null))
					{
						sb = Sb;
						StringBuilder stringBuilder3 = sb;
						handler = new StringBuilder.AppendInterpolatedStringHandler(30, 3, sb);
						handler.AppendLiteral("[Probe]   content[");
						handler.AppendFormatted(j);
						handler.AppendLiteral("] '");
						handler.AppendFormatted(((Object)((Component)((Il2CppArrayBase<RectTransform>)(object)tabs)[j]).gameObject).name);
						handler.AppendLiteral("' active=");
						handler.AppendFormatted(((Component)((Il2CppArrayBase<RectTransform>)(object)tabs)[j]).gameObject.activeSelf);
						stringBuilder3.AppendLine(ref handler);
					}
				}
			}
			if (tabButtons != null && ((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons).Length > 0 && (Object)(object)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[0] != (Object)null)
			{
				Sb.AppendLine("[Probe] --- tab strip ---");
				DumpTree(((Component)((Il2CppArrayBase<SimpleStunButton>)(object)tabButtons)[0]).transform.parent, 0, 80);
			}
			Sb.AppendLine("[Probe] ===== END =====");
			Plugin.L.LogInfo((object)Sb.ToString());
		}

		private static void DumpContents()
		{
			Il2CppReferenceArray<RectTransform> tabs = Menu.Tabs;
			if (tabs == null)
			{
				return;
			}
			for (int i = 0; i < ((Il2CppArrayBase<RectTransform>)(object)tabs).Length; i++)
			{
				if (!((Object)(object)((Il2CppArrayBase<RectTransform>)(object)tabs)[i] == (Object)null))
				{
					Sb.Clear();
					StringBuilder sb = Sb;
					StringBuilder stringBuilder = sb;
					StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(31, 2, sb);
					handler.AppendLiteral("[Probe] ===== CONTENT ");
					handler.AppendFormatted(i);
					handler.AppendLiteral(" '");
					handler.AppendFormatted(((Object)((Component)((Il2CppArrayBase<RectTransform>)(object)tabs)[i]).gameObject).name);
					handler.AppendLiteral("' =====");
					stringBuilder.AppendLine(ref handler);
					DumpTree((Transform)(object)((Il2CppArrayBase<RectTransform>)(object)tabs)[i], 0, 400);
					sb = Sb;
					StringBuilder stringBuilder2 = sb;
					handler = new StringBuilder.AppendInterpolatedStringHandler(32, 1, sb);
					handler.AppendLiteral("[Probe] ===== CONTENT ");
					handler.AppendFormatted(i);
					handler.AppendLiteral(" END =====");
					stringBuilder2.AppendLine(ref handler);
					Plugin.L.LogInfo((object)Sb.ToString());
				}
			}
		}

		private static string Trunc(string s)
		{
			if (s == null)
			{
				return "<null>";
			}
			s = s.Replace("\r", " ").Replace("\n", "\\n");
			if (s.Length <= 90)
			{
				return s;
			}
			return s.Substring(0, 90) + "...";
		}

		private static void DumpTree(Transform t, int depth, int budget)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)t == (Object)null || budget <= 0 || Sb.Length > 90000)
			{
				return;
			}
			string text = "";
			RectTransform component = ((Component)t).GetComponent<RectTransform>();
			if ((Object)(object)component != (Object)null)
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(7, 2);
				defaultInterpolatedStringHandler.AppendLiteral(" size=");
				Rect rect = component.rect;
				defaultInterpolatedStringHandler.AppendFormatted(((Rect)(ref rect)).width, "0");
				defaultInterpolatedStringHandler.AppendLiteral("x");
				rect = component.rect;
				defaultInterpolatedStringHandler.AppendFormatted(((Rect)(ref rect)).height, "0");
				text = defaultInterpolatedStringHandler.ToStringAndClear();
				if ((Object)(object)((Component)t).GetComponent<HorizontalLayoutGroup>() != (Object)null)
				{
					text += " [HLG]";
				}
				if ((Object)(object)((Component)t).GetComponent<VerticalLayoutGroup>() != (Object)null)
				{
					text += " [VLG]";
				}
				if ((Object)(object)((Component)t).GetComponent<GridLayoutGroup>() != (Object)null)
				{
					text += " [GLG]";
				}
			}
			Image component2 = ((Component)t).GetComponent<Image>();
			if ((Object)(object)component2 != (Object)null)
			{
				text = text + " [Image " + (((Object)(object)component2.sprite == (Object)null) ? "-" : ((Object)component2.sprite).name) + "]";
			}
			string value = "";
			TMP_Text component3 = ((Component)t).GetComponent<TMP_Text>();
			if ((Object)(object)component3 != (Object)null)
			{
				value = " text='" + Trunc(component3.text) + "'";
			}
			StringBuilder sb = Sb;
			StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(15, 5, sb);
			handler.AppendLiteral("[Probe] ");
			handler.AppendFormatted(new string(' ', Math.Min(depth * 2, 40)));
			handler.AppendLiteral("- ");
			handler.AppendFormatted(((Object)((Component)t).gameObject).name);
			handler.AppendLiteral(" act=");
			handler.AppendFormatted(((Component)t).gameObject.activeSelf);
			handler.AppendFormatted(text);
			handler.AppendFormatted(value);
			sb.AppendLine(ref handler);
			int childCount = t.childCount;
			for (int i = 0; i < childCount && i < 40; i++)
			{
				DumpTree(t.GetChild(i), depth + 1, budget - 1);
			}
		}
	}
	[BepInPlugin("universalcooldown.ui", "Universal Cooldown UI", "1.1.5")]
	public class Plugin : BasePlugin
	{
		public const string PluginGuid = "universalcooldown.ui";

		public const string PluginName = "Universal Cooldown UI";

		public const string PluginVersion = "1.1.5";

		internal static ManualLogSource L;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<string> Language;

		internal static ConfigEntry<bool> BloodTab;

		internal static ConfigEntry<bool> Probe;

		internal static ConfigEntry<float> SpellRate;

		internal static ConfigEntry<float> WeaponRate;

		internal static ConfigEntry<float> UltimateRate;

		internal static ConfigEntry<string> RatesFile;

		internal static ConfigEntry<int> PollSeconds;

		internal static float ServerSpell = -1f;

		internal static float ServerWeapon = -1f;

		internal static float ServerUltimate = -1f;

		internal static float ServerPhysPower;

		internal static float ServerSpellPower;

		internal static Dictionary<string, float> ServerExtraStats = new Dictionary<string, float>();

		private static DateTime _lastRead = DateTime.MinValue;

		public override void Load()
		{
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Expected O, but got Unknown
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected O, but got Unknown
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Expected O, but got Unknown
			L = ((BasePlugin)this).Log;
			Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Show Bloodcraft bonuses in tooltips and the character window.");
			Language = ((BasePlugin)this).Config.Bind<string>("General", "Language", "auto", "UI language: auto, en or ru.");
			BloodTab = ((BasePlugin)this).Config.Bind<bool>("Tab", "BloodTab", true, "Add the 'Blood' tab to the character window.");
			PollSeconds = ((BasePlugin)this).Config.Bind<int>("Sync", "PollSeconds", 20, "How often the client asks the server for fresh data over chat (seconds). 0 disables polling and relies on server pushes only.");
			SpellRate = ((BasePlugin)this).Config.Bind<float>("Rates", "Spell", 0.14f, "Spell cooldown rate fallback (used when the server file is missing).");
			WeaponRate = ((BasePlugin)this).Config.Bind<float>("Rates", "Weapon", 0.21f, "Weapon cooldown rate fallback.");
			UltimateRate = ((BasePlugin)this).Config.Bind<float>("Rates", "Ultimate", 0.14f, "Ultimate cooldown rate fallback.");
			RatesFile = ((BasePlugin)this).Config.Bind<string>("Sync", "RatesFile", "", "Server file with cooldown rates (universalcooldown_rates.txt). Empty = BepInEx/config/<file>. The Blood tab data files are read from the same folder.");
			Probe = ((BasePlugin)this).Config.Bind<bool>("Debug", "ProbeMenu", false, "Dump the character window hierarchy into the log.");
			Localization.Init(Language.Value);
			Harmony val = new Harmony("local.universalcooldownui");
			MethodInfo method = typeof(TooltipPatch).GetMethod("ApplyFromProperty", BindingFlags.Static | BindingFlags.NonPublic);
			MethodInfo method2 = typeof(TooltipPatch).GetMethod("ApplyFromText", BindingFlags.Static | BindingFlags.NonPublic);
			try
			{
				MethodInfo methodInfo = typeof(TMP_Text).GetProperty("text")?.GetSetMethod(nonPublic: true);
				if (methodInfo != null)
				{
					val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex)
			{
				L.LogWarning((object)("text setter patch failed: " + ex.Message));
			}
			int num = 0;
			MethodInfo[] methods = typeof(TMP_Text).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2.Name != "SetText"))
				{
					try
					{
						val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
					}
					catch
					{
					}
				}
			}
			MenuProbe.Install(val);
			ChatSync.Install(val);
			ManualLogSource l = L;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(53, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("UniversalCooldownUI loaded (lang=");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Localization.Lang>(Localization.Current);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("), SetText patched: ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
			}
			l.LogInfo(val2);
		}

		internal static string RatesPath()
		{
			string value = RatesFile.Value;
			if (!string.IsNullOrWhiteSpace(value))
			{
				return value;
			}
			return Path.Combine(Paths.ConfigPath, "universalcooldown_rates.txt");
		}

		internal static string SyncDirectory()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(RatesPath());
				if (!string.IsNullOrEmpty(directoryName))
				{
					return directoryName;
				}
			}
			catch
			{
			}
			return Paths.ConfigPath;
		}

		internal static void TryReadServerRates()
		{
			if ((DateTime.UtcNow - _lastRead).TotalSeconds < 3.0)
			{
				return;
			}
			_lastRead = DateTime.UtcNow;
			try
			{
				string path = RatesPath();
				try
				{
					ulong localSteamId = BuffsTab.LocalSteamId;
					if (localSteamId != 0L)
					{
						string directoryName = Path.GetDirectoryName(path);
						if (!string.IsNullOrEmpty(directoryName))
						{
							string text = Path.Combine(directoryName, $"universalcooldown_rates_{localSteamId}.txt");
							if (File.Exists(text))
							{
								path = text;
							}
						}
					}
				}
				catch
				{
				}
				if (!File.Exists(path))
				{
					return;
				}
				string[] array = File.ReadAllText(path).Trim().Split('|');
				if (array.Length < 3)
				{
					return;
				}
				if (float.TryParse(array[0].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array[2].Replace(',', '.'), Num