Decompiled source of SimpleUIAdditions v1.2.1

SimpleUIAdditions.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("SimpleUIAdditions")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("Simple UI Additions for the game Mage Arena")]
[assembly: AssemblyTitle("SimpleUIAdditions")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SimpleUIAdditions
{
	[BepInPlugin("com.Delashmit.SimpleUIAdditions", "Simple_UI_Additions", "1.2.0")]
	public class SimpleUIAdditions : BaseUnityPlugin
	{
		private class ActiveCooldown
		{
			public string Name;

			public float EndTime;

			public float Duration;
		}

		public enum CooldownAnchorPosition
		{
			TopLeft,
			BottomLeft,
			BottomRight,
			TopRight,
			Hotbar
		}

		private class SpellInfo
		{
			public string FieldOrPageName;

			public float BaseCooldown;

			public bool IsPageSpell;

			public FieldInfo CachedField;

			public Color SpellColor;

			public SpellInfo(string fieldName, float cooldown, Color color, bool isPage = false)
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				FieldOrPageName = fieldName;
				BaseCooldown = cooldown;
				IsPageSpell = isPage;
				SpellColor = color;
			}
		}

		public static string modsync = "client";

		private static ManualLogSource logger;

		private TextMeshProUGUI healthText;

		private TextMeshProUGUI staminaText;

		private TextMeshProUGUI cooldownText;

		private TextMeshProUGUI speedText;

		private Canvas statsCanvas;

		private Canvas cooldownCanvas;

		private Transform bone014;

		private GameObject localPlayer;

		private GameObject igmObject;

		private GameObject textChatObject;

		private bool wasIgmActiveLastFrame;

		private readonly string[] blockingObjects = new string[4] { "Main", "Lobby", "InGameLobby", "kickplayers" };

		private const float FONT_SIZE = 8f;

		private static readonly Vector3 HEALTH_OFFSET = new Vector3(0.015f, -0.055f, -0.013f);

		private static readonly Vector3 STAMINA_OFFSET = new Vector3(0.032f, -0.055f, -0.013f);

		private static readonly Vector3 SPEED_OFFSET = new Vector3(0.009f, 0.0103f, 0f);

		private static readonly Vector3 COOLDOWN_OFFSET = new Vector3(0.008f, -0.005f, 0f);

		private static readonly Color TEXT_COLOR = new Color(1f, 1f, 1f, 0.75f);

		private const float TEXT_SCALE = 0.002f;

		private ConfigEntry<bool> configEnableDebug;

		private ConfigEntry<bool> configShowCooldowns;

		private ConfigEntry<CooldownAnchorPosition> configCooldownPosition;

		private ConfigEntry<bool> configShowSpeed;

		private FieldInfo healthField;

		private FieldInfo staminaField;

		private FieldInfo crystalCDReductionField;

		private FieldInfo currentSpeedField;

		private Vector3 lastPosition;

		private float lastTime;

		private float manualSpeed;

		private List<ActiveCooldown> activeCooldowns = new List<ActiveCooldown>();

		private static readonly Dictionary<CooldownAnchorPosition, Vector3> cooldownOffsets = new Dictionary<CooldownAnchorPosition, Vector3>
		{
			{
				CooldownAnchorPosition.TopLeft,
				new Vector3(0.008f, -0.005f, 0f)
			},
			{
				CooldownAnchorPosition.BottomLeft,
				new Vector3(0.008f, 0.008f, 0f)
			},
			{
				CooldownAnchorPosition.BottomRight,
				new Vector3(-0.008f, 0.005f, 0f)
			},
			{
				CooldownAnchorPosition.TopRight,
				new Vector3(-0.008f, -0.005f, 0f)
			},
			{
				CooldownAnchorPosition.Hotbar,
				new Vector3(0f, 0.006f, 0f)
			}
		};

		private readonly Dictionary<string, SpellInfo> spellDefinitions = new Dictionary<string, SpellInfo>
		{
			{
				"Fireball",
				new SpellInfo("fbcd", 6f, new Color(1f, 0.3f, 0.2f))
			},
			{
				"Recall",
				new SpellInfo("recallCD", 30f, new Color(0.2f, 0.875f, 1f))
			},
			{
				"Freeze",
				new SpellInfo("frostcd", 8f, new Color(0.4f, 0.8f, 1f))
			},
			{
				"Worm",
				new SpellInfo("wormcd", 25f, new Color(0.22f, 0.22f, 0.902f))
			},
			{
				"Hole",
				new SpellInfo("holecd", 25f, new Color(0.22f, 0.22f, 0.902f))
			},
			{
				"Magic Missile",
				new SpellInfo("wardcd", 6f, new Color(0.608f, 0.196f, 0.906f))
			},
			{
				"Holy Light",
				new SpellInfo("PageHolyLight(Clone)", 40f, new Color(0.922f, 0.839f, 0.125f), isPage: true)
			},
			{
				"Blink",
				new SpellInfo("PageBlink(Clone)", 10f, new Color(0.8f, 1f, 0.8f), isPage: true)
			},
			{
				"Thunderbolt",
				new SpellInfo("PageThunderBolt(Clone)", 15f, new Color(1f, 0.9f, 0f), isPage: true)
			},
			{
				"Dark Blast",
				new SpellInfo("PageDarkBlast(Clone)", 25f, new Color(0.4f, 0f, 0.6f), isPage: true)
			},
			{
				"Wisp",
				new SpellInfo("PageWisp(Clone)", 25f, new Color(1f, 1f, 1f), isPage: true)
			},
			{
				"Rock",
				new SpellInfo("PageRock(Clone)", 25f, new Color(0.75f, 0.5f, 0.1f), isPage: true)
			}
		};

		private PlayerInventory playerInventory;

		private void Awake()
		{
			logger = ((BaseUnityPlugin)this).Logger;
			logger.LogInfo((object)"Plugin com.Delashmit.SimpleUIAdditions is loaded!");
			configEnableDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLogging", false, "Enable detailed debug logging in the BepInEx console");
			configShowCooldowns = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowCooldowns", true, "Enable display of spell cooldowns");
			configCooldownPosition = ((BaseUnityPlugin)this).Config.Bind<CooldownAnchorPosition>("General", "CooldownPosition", CooldownAnchorPosition.TopLeft, "Position of the cooldown text display");
			configShowSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowSpeed", false, "Enable display of movement speed in m/s");
			InitializeReflectionFields();
			CacheSpellFields();
			LogDebug("Plugin initialized", important: false);
		}

		private void InitializeReflectionFields()
		{
			healthField = typeof(PlayerMovement).GetField("playerHealth", BindingFlags.Instance | BindingFlags.NonPublic);
			staminaField = typeof(PlayerMovement).GetField("stamina", BindingFlags.Instance | BindingFlags.NonPublic);
			crystalCDReductionField = typeof(PlayerMovement).GetField("crystalCDReduction", BindingFlags.Instance | BindingFlags.NonPublic);
			currentSpeedField = typeof(PlayerMovement).GetField("currentSpeed", BindingFlags.Instance | BindingFlags.NonPublic);
			if (currentSpeedField == null)
			{
				logger.LogWarning((object)"Could not find 'currentSpeed' field in PlayerMovement! Using manual calculation.");
				FieldInfo[] fields = typeof(PlayerMovement).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					logger.LogInfo((object)("Available field: " + fieldInfo.Name + " (" + fieldInfo.FieldType.Name + ")"));
				}
			}
		}

		private void CacheSpellFields()
		{
			foreach (KeyValuePair<string, SpellInfo> spellDefinition in spellDefinitions)
			{
				if (spellDefinition.Value.IsPageSpell)
				{
					continue;
				}
				spellDefinition.Value.CachedField = typeof(PlayerInventory).GetField(spellDefinition.Value.FieldOrPageName, BindingFlags.Instance | BindingFlags.NonPublic);
				if (spellDefinition.Value.CachedField == null)
				{
					spellDefinition.Value.CachedField = typeof(PlayerMovement).GetField(spellDefinition.Value.FieldOrPageName, BindingFlags.Instance | BindingFlags.NonPublic);
					if (spellDefinition.Value.CachedField != null)
					{
						LogDebug("Found " + spellDefinition.Key + " cooldown field in PlayerMovement", important: false);
					}
				}
				else
				{
					LogDebug("Found " + spellDefinition.Key + " cooldown field in PlayerInventory", important: false);
				}
				if (spellDefinition.Value.CachedField == null)
				{
					LogDebug("Could not find " + spellDefinition.Key + " cooldown field in PlayerInventory or PlayerMovement", important: true);
					LogDebug("PlayerInventory fields:", important: true);
					FieldInfo[] fields = typeof(PlayerInventory).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						LogDebug("- " + fieldInfo.Name + " (" + fieldInfo.FieldType.Name + ")", important: true);
					}
					LogDebug("PlayerMovement fields:", important: true);
					FieldInfo[] fields2 = typeof(PlayerMovement).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo2 in fields2)
					{
						LogDebug("- " + fieldInfo2.Name + " (" + fieldInfo2.FieldType.Name + ")", important: true);
					}
				}
			}
		}

		private void Update()
		{
			try
			{
				FindAndInitializePlayer();
				if ((Object)(object)localPlayer != (Object)null)
				{
					FindAndInitializeBone();
					if ((Object)(object)statsCanvas == (Object)null && (Object)(object)bone014 != (Object)null)
					{
						InitializeStatsCanvas();
					}
					if ((Object)(object)statsCanvas != (Object)null)
					{
						InitializeHealthText();
						InitializeStaminaText();
					}
					HandleCooldownCanvas();
					FindPlayerInventory();
					UpdateAllValues();
				}
				else
				{
					CleanupUI();
				}
				HandleTextChatVisibility();
			}
			catch (Exception arg)
			{
				logger.LogError((object)$"[Error] {arg}");
			}
		}

		private void HandleTextChatVisibility()
		{
			if ((Object)(object)igmObject == (Object)null)
			{
				igmObject = GameObject.Find("IGM");
				if ((Object)(object)igmObject != (Object)null)
				{
					LogDebug("Found IGM object", important: false);
					wasIgmActiveLastFrame = igmObject.activeInHierarchy;
				}
			}
			if ((Object)(object)textChatObject == (Object)null)
			{
				GameObject val = GameObject.Find("Canvas (1)");
				if ((Object)(object)val != (Object)null)
				{
					Transform val2 = val.transform.Find("TextChat");
					if ((Object)(object)val2 != (Object)null)
					{
						textChatObject = ((Component)val2).gameObject;
						LogDebug("Found TextChat object", important: false);
					}
				}
			}
			if ((Object)(object)igmObject == (Object)null || (Object)(object)textChatObject == (Object)null)
			{
				return;
			}
			bool activeInHierarchy = igmObject.activeInHierarchy;
			if (activeInHierarchy != wasIgmActiveLastFrame)
			{
				bool flag = true;
				string[] array = blockingObjects;
				foreach (string text in array)
				{
					GameObject val3 = GameObject.Find(text);
					if ((Object)(object)val3 != (Object)null && val3.activeInHierarchy)
					{
						flag = false;
						LogDebug("Not adjusting TextChat because " + text + " is active", important: false);
						break;
					}
				}
				if (flag && textChatObject.activeSelf != activeInHierarchy)
				{
					textChatObject.SetActive(activeInHierarchy);
					LogDebug($"Set TextChat active state to: {activeInHierarchy}", important: false);
				}
			}
			wasIgmActiveLastFrame = activeInHierarchy;
		}

		private void FindAndInitializePlayer()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)localPlayer == (Object)null || !Object.op_Implicit((Object)(object)localPlayer))
			{
				localPlayer = FindLocalPlayer();
				if ((Object)(object)localPlayer != (Object)null)
				{
					LogDebug("Found local player!", important: false);
					lastPosition = localPlayer.transform.position;
					lastTime = Time.time;
				}
			}
		}

		private void FindAndInitializeBone()
		{
			if (((Object)(object)bone014 == (Object)null || !Object.op_Implicit((Object)(object)bone014)) && (Object)(object)localPlayer != (Object)null)
			{
				bone014 = FindBone014();
				if ((Object)(object)bone014 != (Object)null)
				{
					LogDebug("Found Bone.014!", important: false);
				}
			}
		}

		private void InitializeStatsCanvas()
		{
			if ((Object)(object)statsCanvas == (Object)null && (Object)(object)bone014 != (Object)null)
			{
				statsCanvas = CreateStatsCanvas();
				if ((Object)(object)statsCanvas != (Object)null)
				{
					LogDebug("Created stats canvas!", important: false);
				}
				else
				{
					LogDebug("Failed to create stats canvas!", important: true);
				}
			}
		}

		private void InitializeHealthText()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)statsCanvas != (Object)null && ((Object)(object)healthText == (Object)null || !Object.op_Implicit((Object)(object)healthText)))
			{
				healthText = CreateWorldText(((Component)statsCanvas).transform, "HealthText", HEALTH_OFFSET);
				if ((Object)(object)healthText != (Object)null)
				{
					LogDebug("[Position] Health Text: " + GetTransformInfo(((TMP_Text)healthText).transform), important: false);
				}
			}
		}

		private void InitializeStaminaText()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)statsCanvas != (Object)null && ((Object)(object)staminaText == (Object)null || !Object.op_Implicit((Object)(object)staminaText)))
			{
				staminaText = CreateWorldText(((Component)statsCanvas).transform, "StaminaText", STAMINA_OFFSET);
				if ((Object)(object)staminaText != (Object)null)
				{
					LogDebug("[Position] Stamina Text: " + GetTransformInfo(((TMP_Text)staminaText).transform), important: false);
				}
			}
		}

		private void HandleCooldownCanvas()
		{
			if (configShowCooldowns.Value)
			{
				if ((Object)(object)cooldownCanvas == (Object)null || !Object.op_Implicit((Object)(object)cooldownCanvas))
				{
					cooldownCanvas = CreateCooldownCanvas();
					if ((Object)(object)cooldownCanvas != (Object)null)
					{
						LogDebug("Created cooldown canvas!", important: false);
					}
				}
				if ((Object)(object)cooldownCanvas != (Object)null)
				{
					InitializeCooldownText();
					InitializeSpeedText();
				}
			}
			else if ((Object)(object)cooldownCanvas != (Object)null)
			{
				CleanupCooldownCanvas();
			}
		}

		private void InitializeCooldownText()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cooldownText == (Object)null || !Object.op_Implicit((Object)(object)cooldownText))
			{
				cooldownText = CreateWorldText(((Component)cooldownCanvas).transform, "CooldownText", COOLDOWN_OFFSET);
				((TMP_Text)cooldownText).alignment = (TextAlignmentOptions)514;
				((TMP_Text)cooldownText).fontSize = 0.2f;
				LogDebug("[Position] Cooldown Text: " + GetTransformInfo(((TMP_Text)cooldownText).transform), important: false);
			}
		}

		private void InitializeSpeedText()
		{
			//IL_004a: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			if (configShowSpeed.Value && ((Object)(object)speedText == (Object)null || !Object.op_Implicit((Object)(object)speedText)))
			{
				speedText = CreateWorldText(((Component)cooldownCanvas).transform, "SpeedText", SPEED_OFFSET);
				((TMP_Text)speedText).alignment = (TextAlignmentOptions)514;
				((TMP_Text)speedText).fontSize = 0.2f;
				((TMP_Text)speedText).transform.localRotation = Quaternion.Euler(0f, 0f, 180f);
				((Graphic)speedText).color = new Color(1f, 1f, 1f, 0.8f);
				((TMP_Text)speedText).text = "0.00 m/s";
				LogDebug("[Position] Speed Text: " + GetTransformInfo(((TMP_Text)speedText).transform), important: false);
			}
			else if (!configShowSpeed.Value && (Object)(object)speedText != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)speedText).gameObject);
				speedText = null;
			}
		}

		private void CleanupCooldownCanvas()
		{
			Object.Destroy((Object)(object)((Component)cooldownCanvas).gameObject);
			cooldownCanvas = null;
			cooldownText = null;
			if ((Object)(object)speedText != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)speedText).gameObject);
				speedText = null;
			}
		}

		private void FindPlayerInventory()
		{
			if ((Object)(object)playerInventory == (Object)null)
			{
				playerInventory = localPlayer.GetComponent<PlayerInventory>();
				if ((Object)(object)playerInventory != (Object)null)
				{
					LogDebug("Found PlayerInventory component", important: false);
				}
			}
		}

		private void UpdateAllValues()
		{
			UpdateValues();
			if (configShowCooldowns.Value && (Object)(object)cooldownCanvas != (Object)null)
			{
				UpdateCooldowns();
				UpdateCooldownPosition();
			}
			if (configShowSpeed.Value && (Object)(object)speedText != (Object)null)
			{
				UpdateSpeed();
			}
		}

		private void UpdateSpeed()
		{
			if (currentSpeedField != null)
			{
				UpdateSpeedValue();
			}
			else
			{
				CalculateManualSpeed();
			}
		}

		private void UpdateSpeedValue()
		{
			try
			{
				if (!((Object)(object)localPlayer == (Object)null) && !(currentSpeedField == null) && !((Object)(object)speedText == (Object)null))
				{
					PlayerMovement component = localPlayer.GetComponent<PlayerMovement>();
					if (!((Object)(object)component == (Object)null))
					{
						float num = (float)currentSpeedField.GetValue(component);
						((TMP_Text)speedText).text = $"{num:0.00} m/s";
						LogDebug($"Reflection speed: {num:0.00} m/s", important: false);
					}
				}
			}
			catch (Exception ex)
			{
				logger.LogError((object)("Error updating speed: " + ex.Message));
				currentSpeedField = null;
			}
		}

		private void CalculateManualSpeed()
		{
			//IL_004f: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)speedText == (Object)null))
			{
				float num = Time.time - lastTime;
				if (num > 0.1f)
				{
					float num2 = Vector3.Distance(localPlayer.transform.position, lastPosition);
					manualSpeed = num2 / num;
					((TMP_Text)speedText).text = $"{manualSpeed:0.00} m/s";
					LogDebug($"Manual speed: {manualSpeed:0.00} m/s", important: false);
					lastPosition = localPlayer.transform.position;
					lastTime = Time.time;
				}
			}
		}

		private Canvas CreateStatsCanvas()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				LogDebug("Attempting to create stats canvas...", important: true);
				if ((Object)(object)bone014 == (Object)null)
				{
					LogDebug("Bone014 is null - cannot create canvas", important: true);
					return null;
				}
				GameObject val = new GameObject("StatsCanvas");
				val.transform.SetParent(bone014);
				val.transform.localPosition = Vector3.zero;
				val.transform.localRotation = Quaternion.Euler(0f, 270f, 0f);
				val.transform.localScale = Vector3.one;
				Canvas val2 = val.AddComponent<Canvas>();
				val2.renderMode = (RenderMode)2;
				Camera val3 = Camera.main;
				if ((Object)(object)val3 == (Object)null)
				{
					LogDebug("Main camera not found, searching for any camera...", important: true);
					val3 = Object.FindObjectOfType<Camera>();
				}
				if ((Object)(object)val3 == (Object)null)
				{
					LogDebug("No camera found at all!", important: true);
					Object.Destroy((Object)(object)val);
					return null;
				}
				val2.worldCamera = val3;
				val.AddComponent<CanvasScaler>();
				val.AddComponent<GraphicRaycaster>();
				LogDebug("Stats canvas created successfully", important: true);
				return val2;
			}
			catch (Exception arg)
			{
				logger.LogError((object)$"Error creating stats canvas: {arg}");
				return null;
			}
		}

		private Canvas CreateCooldownCanvas()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Transform val = localPlayer.transform.Find("Main Camera");
				if ((Object)(object)val == (Object)null)
				{
					throw new Exception("Main Camera not found");
				}
				Transform val2 = val.Find("ui");
				if ((Object)(object)val2 == (Object)null)
				{
					throw new Exception("ui not found");
				}
				Transform val3 = val2.Find("Plane");
				if ((Object)(object)val3 == (Object)null)
				{
					throw new Exception("Plane not found");
				}
				GameObject val4 = new GameObject("CooldownCanvas");
				val4.transform.SetParent(val3);
				val4.transform.localPosition = Vector3.zero;
				val4.transform.localRotation = Quaternion.identity;
				val4.transform.localScale = Vector3.one;
				Canvas val5 = val4.AddComponent<Canvas>();
				val5.renderMode = (RenderMode)2;
				val5.worldCamera = Camera.main;
				CanvasScaler val6 = val4.AddComponent<CanvasScaler>();
				val6.dynamicPixelsPerUnit = 300f;
				val6.referencePixelsPerUnit = 1f;
				val4.AddComponent<GraphicRaycaster>();
				return val5;
			}
			catch (Exception ex)
			{
				LogDebug("Failed to create cooldown canvas: " + ex.Message, important: false);
				return null;
			}
		}

		private TextMeshProUGUI CreateWorldText(Transform parent, string name, Vector3 offset)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)parent == (Object)null)
				{
					LogDebug("Cannot create " + name + " text - parent transform is null", important: true);
					return null;
				}
				GameObject val = new GameObject(name);
				val.transform.SetParent(parent);
				val.transform.localPosition = offset;
				if (name == "CooldownText")
				{
					val.transform.localRotation = Quaternion.Euler(0f, 0f, 180f);
				}
				else if (name == "SpeedText")
				{
					val.transform.localRotation = Quaternion.Euler(0f, 0f, 180f);
				}
				else
				{
					val.transform.localRotation = Quaternion.Euler(0f, 0f, 90f);
				}
				val.transform.localScale = Vector3.one * 0.002f;
				TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
				TextMeshProUGUI val3 = val2;
				if (1 == 0)
				{
				}
				string text = name switch
				{
					"HealthText" => "HP: 100", 
					"StaminaText" => "ST: 100", 
					"SpeedText" => "0.00 m/s", 
					_ => "INIT", 
				};
				if (1 == 0)
				{
				}
				((TMP_Text)val3).text = text;
				((TMP_Text)val2).fontSize = 8f;
				((TMP_Text)val2).alignment = (TextAlignmentOptions)((name == "CooldownText") ? 513 : 514);
				((Graphic)val2).raycastTarget = false;
				((TMP_Text)val2).richText = name == "CooldownText";
				TextMeshProUGUI val4 = val2;
				if (1 == 0)
				{
				}
				Color color = (Color)(name switch
				{
					"HealthText" => new Color(1f, 0.2f, 0.2f, 0.8f), 
					"StaminaText" => new Color(0.2f, 0.8f, 0.2f, 0.8f), 
					"SpeedText" => new Color(1f, 1f, 1f, 0.8f), 
					_ => TEXT_COLOR, 
				});
				if (1 == 0)
				{
				}
				((Graphic)val4).color = color;
				Outline val5 = val.AddComponent<Outline>();
				((Shadow)val5).effectColor = new Color(0f, 0f, 0f, 0.8f);
				((Shadow)val5).effectDistance = new Vector2(0.1f, 0.1f);
				LogDebug($"{name} created at position: {val.transform.localPosition}", important: false);
				return val2;
			}
			catch (Exception arg)
			{
				logger.LogError((object)$"Error creating {name} text: {arg}");
				return null;
			}
		}

		private void UpdateCooldowns()
		{
			if ((Object)(object)playerInventory == (Object)null)
			{
				return;
			}
			PlayerMovement component = localPlayer.GetComponent<PlayerMovement>();
			float cdReduction = (((Object)(object)component != (Object)null && crystalCDReductionField != null) ? ((float)crystalCDReductionField.GetValue(component)) : 0f);
			foreach (KeyValuePair<string, SpellInfo> spellDefinition in spellDefinitions)
			{
				try
				{
					if (spellDefinition.Value.IsPageSpell)
					{
						CheckPageSpellCooldown(spellDefinition.Key, spellDefinition.Value, cdReduction);
					}
					else
					{
						CheckDefaultSpellCooldown(spellDefinition.Key, spellDefinition.Value, cdReduction);
					}
				}
				catch (Exception ex)
				{
					LogDebug("Error checking " + spellDefinition.Key + " cooldown: " + ex.Message, important: false);
				}
			}
			activeCooldowns.RemoveAll((ActiveCooldown cd) => Time.time >= cd.EndTime);
			UpdateCooldownDisplay();
		}

		private void UpdateCooldownPosition()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cooldownText != (Object)null)
			{
				((TMP_Text)cooldownText).transform.localPosition = cooldownOffsets[configCooldownPosition.Value];
				switch (configCooldownPosition.Value)
				{
				case CooldownAnchorPosition.TopLeft:
				case CooldownAnchorPosition.BottomLeft:
					((TMP_Text)cooldownText).alignment = (TextAlignmentOptions)513;
					break;
				case CooldownAnchorPosition.BottomRight:
				case CooldownAnchorPosition.TopRight:
					((TMP_Text)cooldownText).alignment = (TextAlignmentOptions)516;
					break;
				case CooldownAnchorPosition.Hotbar:
					((TMP_Text)cooldownText).alignment = (TextAlignmentOptions)514;
					break;
				}
			}
		}

		private void CheckDefaultSpellCooldown(string spellName, SpellInfo spellInfo, float cdReduction)
		{
			if (spellInfo.CachedField == null)
			{
				return;
			}
			object obj = ((spellInfo.CachedField.DeclaringType == typeof(PlayerInventory)) ? ((object)playerInventory) : ((object)localPlayer.GetComponent<PlayerMovement>()));
			if (obj == null)
			{
				return;
			}
			float num = (float)spellInfo.CachedField.GetValue(obj);
			float num2 = Math.Max(0.1f, spellInfo.BaseCooldown - cdReduction);
			float num3 = num2 - (Time.time - num);
			if (num3 > 0f)
			{
				ActiveCooldown activeCooldown = activeCooldowns.Find((ActiveCooldown cd) => cd.Name == spellName);
				if (activeCooldown != null)
				{
					activeCooldown.EndTime = num + num2;
					activeCooldown.Duration = num2;
					return;
				}
				activeCooldowns.Add(new ActiveCooldown
				{
					Name = spellName,
					EndTime = num + num2,
					Duration = num2
				});
				LogDebug($"Started {spellName} cooldown: {num2}s (Last cast: {num})", important: false);
			}
		}

		private void CheckPageSpellCooldown(string spellName, SpellInfo spellInfo, float cdReduction)
		{
			try
			{
				GameObject obj = localPlayer;
				Transform val = ((obj != null) ? obj.transform.Find("pikupact") : null);
				if ((Object)(object)val == (Object)null)
				{
					LogDebug(spellName + ": pikupact not found", important: false);
					return;
				}
				Transform val2 = null;
				for (int i = 0; i < val.childCount; i++)
				{
					if (((Object)val.GetChild(i)).name == spellInfo.FieldOrPageName)
					{
						val2 = val.GetChild(i);
						break;
					}
				}
				if ((Object)(object)val2 == (Object)null)
				{
					LogDebug(spellName + ": Page not found in pikupact", important: false);
					return;
				}
				PageController componentInChildren = ((Component)val2).GetComponentInChildren<PageController>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					LogDebug(spellName + ": PageController missing", important: false);
					return;
				}
				FieldInfo field = typeof(PageController).GetField("PageCoolDownTimer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					LogDebug(spellName + ": PageCoolDownTimer field not found", important: true);
					LogDebug("Available fields in PageController:", important: true);
					FieldInfo[] fields = typeof(PageController).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						LogDebug("- " + fieldInfo.Name, important: true);
					}
					return;
				}
				float num = (float)field.GetValue(componentInChildren);
				float num2 = Math.Max(0.1f, spellInfo.BaseCooldown - cdReduction);
				float num3 = num2 - (Time.time - num);
				if (num3 > 0f)
				{
					ActiveCooldown activeCooldown = activeCooldowns.Find((ActiveCooldown cd) => cd.Name == spellName);
					if (activeCooldown != null)
					{
						activeCooldown.EndTime = num + num2;
						activeCooldown.Duration = num2;
						return;
					}
					activeCooldowns.Add(new ActiveCooldown
					{
						Name = spellName,
						EndTime = num + num2,
						Duration = num2
					});
					LogDebug($"Started {spellName} cooldown: {num2}s", important: true);
				}
			}
			catch (Exception ex)
			{
				LogDebug(spellName + " error: " + ex.Message, important: true);
			}
		}

		private void UpdateCooldownDisplay()
		{
			//IL_009c: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cooldownText == (Object)null)
			{
				return;
			}
			if (activeCooldowns.Count == 0)
			{
				((TMP_Text)cooldownText).text = "";
				return;
			}
			string text = "";
			foreach (ActiveCooldown activeCooldown in activeCooldowns)
			{
				float num = activeCooldown.EndTime - Time.time;
				if (num > 0f)
				{
					SpellInfo value;
					Color val = (spellDefinitions.TryGetValue(activeCooldown.Name, out value) ? value.SpellColor : Color.white);
					string arg = ColorUtility.ToHtmlStringRGBA(val);
					text += $"<color=#{arg}>{activeCooldown.Name}</color>: <color=#FFFFFF>{num:0.0}s</color>\n";
				}
			}
			((TMP_Text)cooldownText).text = text.TrimEnd(Array.Empty<char>());
		}

		private void UpdateValues()
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)localPlayer == (Object)null)
				{
					return;
				}
				PlayerMovement component = localPlayer.GetComponent<PlayerMovement>();
				if (!((Object)(object)component == (Object)null))
				{
					if ((Object)(object)healthText != (Object)null && healthField != null)
					{
						float num = (float)healthField.GetValue(component);
						((TMP_Text)healthText).text = $"HP:{num:0}";
						((Graphic)healthText).color = ((num < 30f) ? new Color(1f, 0.2f, 0.2f, 0.8f) : new Color(1f, 1f, 1f, 0.8f));
					}
					if ((Object)(object)staminaText != (Object)null && staminaField != null)
					{
						float num2 = (float)staminaField.GetValue(component) * 10f;
						((TMP_Text)staminaText).text = $"ST: {num2:0}";
						((Graphic)staminaText).color = ((num2 < 30f) ? new Color(1f, 0.5f, 0.2f, 0.8f) : new Color(1f, 1f, 1f, 0.8f));
					}
				}
			}
			catch (Exception arg)
			{
				logger.LogError((object)$"Error updating values: {arg}");
			}
		}

		private void LogDebug(string message, bool important)
		{
			if (configEnableDebug.Value && (important || Time.frameCount % 60 == 0))
			{
				logger.LogInfo((object)("[Debug] " + message));
			}
		}

		private GameObject FindLocalPlayer()
		{
			GameObject[] array = Object.FindObjectsOfType<GameObject>();
			foreach (GameObject val in array)
			{
				if (((Object)val).name == "Player(Clone)" && (Object)(object)val.transform.Find("armz") != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private Transform FindBone014()
		{
			if ((Object)(object)localPlayer == (Object)null)
			{
				return null;
			}
			return localPlayer.transform.Find("Main Camera/ui/ionknow/Armature/Bone.014");
		}

		private string GetTransformInfo(Transform t)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)t == (Object)null)
			{
				return "null";
			}
			return $"Position: {t.localPosition} | Rotation: {t.localEulerAngles} | Scale: {t.localScale}";
		}

		private void CleanupUI()
		{
			if ((Object)(object)healthText != (Object)null && Object.op_Implicit((Object)(object)healthText))
			{
				Object.Destroy((Object)(object)((Component)healthText).gameObject);
				healthText = null;
			}
			if ((Object)(object)staminaText != (Object)null && Object.op_Implicit((Object)(object)staminaText))
			{
				Object.Destroy((Object)(object)((Component)staminaText).gameObject);
				staminaText = null;
			}
			if ((Object)(object)cooldownText != (Object)null && Object.op_Implicit((Object)(object)cooldownText))
			{
				Object.Destroy((Object)(object)((Component)cooldownText).gameObject);
				cooldownText = null;
			}
			if ((Object)(object)statsCanvas != (Object)null && Object.op_Implicit((Object)(object)statsCanvas))
			{
				Object.Destroy((Object)(object)((Component)statsCanvas).gameObject);
				statsCanvas = null;
			}
			if ((Object)(object)cooldownCanvas != (Object)null && Object.op_Implicit((Object)(object)cooldownCanvas))
			{
				Object.Destroy((Object)(object)((Component)cooldownCanvas).gameObject);
				cooldownCanvas = null;
			}
			if ((Object)(object)speedText != (Object)null && Object.op_Implicit((Object)(object)speedText))
			{
				Object.Destroy((Object)(object)((Component)speedText).gameObject);
				speedText = null;
			}
			bone014 = null;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "com.Delashmit.SimpleUIAdditions";

		public const string PLUGIN_NAME = "Simple_UI_Additions";

		public const string PLUGIN_VERSION = "1.2.0";
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "SimpleUIAdditions";

		public const string PLUGIN_NAME = "Simple UI Additions for the game Mage Arena";

		public const string PLUGIN_VERSION = "1.2.0";
	}
}