Decompiled source of CosmeticTokenCountHUD v4.0.0

CosmeticTokenCountHUD.dll

Decompiled 2 days 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 HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("REPOJP")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("zabuMod")]
[assembly: AssemblyTitle("zabuMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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 REPOJP.CosmeticTokenCountHUD
{
	[BepInPlugin("REPOJP.CosmeticTokenCountHUD", "CosmeticTokenCountHUD", "4.0.0")]
	public class CosmeticTokenCountHUDPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "REPOJP.CosmeticTokenCountHUD";

		public const string PluginName = "CosmeticTokenCountHUD";

		public const string PluginVersion = "4.0.0";

		internal static ManualLogSource Log;

		internal static bool PendingRefresh;

		internal static ConfigEntry<bool> Enable;

		internal static ConfigEntry<bool> ShowDebugLog;

		internal static ConfigEntry<float> RefreshIntervalSeconds;

		internal static ConfigEntry<bool> ShowOnlyInShop;

		internal static ConfigEntry<bool> HideWhenNoToken;

		internal static ConfigEntry<bool> ShowZeroCountRarity;

		internal static ConfigEntry<HudAnchor> Anchor;

		internal static ConfigEntry<float> OffsetX;

		internal static ConfigEntry<float> OffsetY;

		internal static ConfigEntry<int> FontSize;

		internal static ConfigEntry<float> BackgroundOpacity;

		internal static ConfigEntry<float> TextOpacity;

		internal static ConfigEntry<int> SortingOrder;

		internal static ConfigEntry<float> LineSpacing;

		internal static ConfigEntry<float> PaddingX;

		internal static ConfigEntry<float> PaddingY;

		internal static ConfigEntry<float> Width;

		internal static ConfigEntry<bool> AutoResizeWidth;

		internal static ConfigEntry<HudTextAlign> TextAlign;

		internal static ConfigEntry<DisplayOrderMode> DisplayOrder;

		internal static ConfigEntry<string> CustomDisplayOrder;

		internal static ConfigEntry<string> TitleText;

		internal static ConfigEntry<string> CommonLabel;

		internal static ConfigEntry<string> UncommonLabel;

		internal static ConfigEntry<string> RareLabel;

		internal static ConfigEntry<string> UltraRareLabel;

		internal static ConfigEntry<bool> UseRarityTextColor;

		internal static ConfigEntry<string> CommonColor;

		internal static ConfigEntry<string> UncommonColor;

		internal static ConfigEntry<string> RareColor;

		internal static ConfigEntry<string> UltraRareColor;

		internal static ConfigEntry<string> BackgroundColor;

		internal static ConfigEntry<bool> RefreshOnCosmeticTokenUISetup;

		internal static ConfigEntry<bool> RefreshOnCosmeticShopMachineInteract;

		internal static Type MetaManagerType;

		internal static Type SemiFuncType;

		internal static Type RunManagerType;

		internal static Type GameDirectorType;

		internal static Type ShopManagerType;

		internal static Type CosmeticShopMachineType;

		internal static Type CosmeticTokenUIType;

		internal static FieldInfo MetaManagerInstanceField;

		internal static FieldInfo CosmeticTokensField;

		internal static FieldInfo RunManagerInstanceField;

		internal static FieldInfo GameDirectorInstanceField;

		internal static FieldInfo GameDirectorCurrentStateField;

		internal static MethodInfo RunIsShopMethod;

		private Harmony harmony;

		private void Awake()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			try
			{
				if ((Object)(object)((Component)this).transform.parent != (Object)null)
				{
					((Component)this).transform.parent = null;
				}
				((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
				Log = ((BaseUnityPlugin)this).Logger;
				BindConfig();
				CacheGameTypes();
				if ((Object)(object)((Component)this).GetComponent<CosmeticTokenCountHUDController>() == (Object)null)
				{
					((Component)this).gameObject.AddComponent<CosmeticTokenCountHUDController>();
				}
				harmony = new Harmony("REPOJP.CosmeticTokenCountHUD");
				ApplyPatches();
				WriteDebugLog("Plugin loaded. Version=4.0.0");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Awake\n" + ex));
			}
		}

		private void OnDestroy()
		{
			try
			{
				if (harmony != null)
				{
					harmony.UnpatchSelf();
					harmony = null;
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failure: OnDestroy\n" + ex));
			}
		}

		private void BindConfig()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Expected O, but got Unknown
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Expected O, but got Unknown
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Expected O, but got Unknown
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Expected O, but got Unknown
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Expected O, but got Unknown
			Enable = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable", true, "Enable the HUD display.HUD表示を有効化します");
			ShowDebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowDebugLog", false, "Show debug logs.デバッグログを表示します");
			RefreshIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RefreshIntervalSeconds", 0.35f, new ConfigDescription("Refresh interval in seconds.更新間隔の秒数です", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
			ShowOnlyInShop = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowOnlyInShop", true, "Show only while you are in the shop.ショップ中のみ表示します");
			HideWhenNoToken = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "HideWhenNoToken", true, "Hide the HUD when you have no cosmetic tokens.コスメトークンを持っていない時にHUDを非表示にします");
			ShowZeroCountRarity = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowZeroCountRarity", true, "Show rarity rows even when the count is zero.0枚のレアリティも表示します");
			Anchor = ((BaseUnityPlugin)this).Config.Bind<HudAnchor>("Display", "Anchor", HudAnchor.BottomRight, "HUD anchor position.HUDの基準位置です");
			OffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "OffsetX", -40f, "Horizontal offset from the anchor.基準位置からの横方向オフセットです");
			OffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "OffsetY", 160f, "Vertical offset from the anchor.基準位置からの縦方向オフセットです");
			FontSize = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "FontSize", 18, new ConfigDescription("Text font size.文字サイズです", (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 48), Array.Empty<object>()));
			BackgroundOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "BackgroundOpacity", 0.35f, new ConfigDescription("Background opacity.背景の不透明度です", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			TextOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "TextOpacity", 1f, new ConfigDescription("Text opacity.文字の不透明度です", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()));
			SortingOrder = ((BaseUnityPlugin)this).Config.Bind<int>("Display", "SortingOrder", 300, new ConfigDescription("Canvas sorting order.Canvasの描画順です", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
			LineSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "LineSpacing", 4f, new ConfigDescription("Spacing between lines.行間です", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 24f), Array.Empty<object>()));
			PaddingX = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "PaddingX", 12f, new ConfigDescription("Horizontal padding.横方向の余白です", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			PaddingY = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "PaddingY", 10f, new ConfigDescription("Vertical padding.縦方向の余白です", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), Array.Empty<object>()));
			Width = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "Width", 260f, new ConfigDescription("HUD width.HUDの横幅です", (AcceptableValueBase)(object)new AcceptableValueRange<float>(120f, 800f), Array.Empty<object>()));
			AutoResizeWidth = ((BaseUnityPlugin)this).Config.Bind<bool>("Layout", "AutoResizeWidth", true, "Automatically widen the HUD when text is long.文字が長い場合にHUDの横幅を自動調整します");
			TextAlign = ((BaseUnityPlugin)this).Config.Bind<HudTextAlign>("Layout", "TextAlign", HudTextAlign.Left, "Text alignment.文字揃えです");
			DisplayOrder = ((BaseUnityPlugin)this).Config.Bind<DisplayOrderMode>("Layout", "DisplayOrder", DisplayOrderMode.LowToHigh, "Rarity display order.レアリティの表示順です");
			CustomDisplayOrder = ((BaseUnityPlugin)this).Config.Bind<string>("Layout", "CustomDisplayOrder", "Common,Uncommon,Rare,UltraRare", "Custom display order when DisplayOrder is Custom.DisplayOrderがCustomの時の表示順です");
			TitleText = ((BaseUnityPlugin)this).Config.Bind<string>("Text", "TitleText", "Cosmetic Tokens", "HUD title text.HUDタイトル文字列です");
			CommonLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Text", "CommonLabel", "Common", "Common rarity label.Commonレアリティの表示名です");
			UncommonLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Text", "UncommonLabel", "Uncommon", "Uncommon rarity label.Uncommonレアリティの表示名です");
			RareLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Text", "RareLabel", "Rare", "Rare rarity label.Rareレアリティの表示名です");
			UltraRareLabel = ((BaseUnityPlugin)this).Config.Bind<string>("Text", "UltraRareLabel", "UltraRare", "UltraRare rarity label.UltraRareレアリティの表示名です");
			UseRarityTextColor = ((BaseUnityPlugin)this).Config.Bind<bool>("Color", "UseRarityTextColor", true, "Use different text colors for each rarity.レアリティごとに文字色を変えます");
			CommonColor = ((BaseUnityPlugin)this).Config.Bind<string>("Color", "CommonColor", "#00C807", "Common text color in hex.Common文字色の16進数指定です");
			UncommonColor = ((BaseUnityPlugin)this).Config.Bind<string>("Color", "UncommonColor", "#0398CB", "Uncommon text color in hex.Uncommon文字色の16進数指定です");
			RareColor = ((BaseUnityPlugin)this).Config.Bind<string>("Color", "RareColor", "#BD06BB", "Rare text color in hex.Rare文字色の16進数指定です");
			UltraRareColor = ((BaseUnityPlugin)this).Config.Bind<string>("Color", "UltraRareColor", "#B89005", "UltraRare text color in hex.UltraRare文字色の16進数指定です");
			BackgroundColor = ((BaseUnityPlugin)this).Config.Bind<string>("Color", "BackgroundColor", "#000000", "Background color in hex.背景色の16進数指定です");
			ApplyTokenColorDefaults();
			RefreshOnCosmeticTokenUISetup = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "RefreshOnCosmeticTokenUISetup", false, "Refresh when vanilla CosmeticTokenUI is refreshed.バニラのCosmeticTokenUI更新時にHUDも更新します");
			RefreshOnCosmeticShopMachineInteract = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "RefreshOnCosmeticShopMachineInteract", true, "Refresh immediately when the cosmetic shop machine is used.コスメショップマシン使用時に即時更新します");
		}

		private void ApplyTokenColorDefaults()
		{
			try
			{
				SetColorIfOldDefault(CommonColor, "#FFFFFF", "#00C807");
				SetColorIfOldDefault(UncommonColor, "#6EFF6E", "#0398CB");
				SetColorIfOldDefault(RareColor, "#6EA8FF", "#BD06BB");
				SetColorIfOldDefault(UltraRareColor, "#D66EFF", "#B89005");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failure: ApplyTokenColorDefaults\n" + ex));
			}
		}

		private void SetColorIfOldDefault(ConfigEntry<string> entry, string oldValue, string newValue)
		{
			if (entry != null && string.Equals(NormalizeHexColor(entry.Value), NormalizeHexColor(oldValue), StringComparison.OrdinalIgnoreCase))
			{
				entry.Value = newValue;
			}
		}

		private string NormalizeHexColor(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			string text = value.Trim();
			if (!text.StartsWith("#"))
			{
				text = "#" + text;
			}
			return text;
		}

		private void CacheGameTypes()
		{
			MetaManagerType = AccessTools.TypeByName("MetaManager");
			SemiFuncType = AccessTools.TypeByName("SemiFunc");
			RunManagerType = AccessTools.TypeByName("RunManager");
			GameDirectorType = AccessTools.TypeByName("GameDirector");
			ShopManagerType = AccessTools.TypeByName("ShopManager");
			CosmeticShopMachineType = AccessTools.TypeByName("CosmeticShopMachine");
			CosmeticTokenUIType = AccessTools.TypeByName("CosmeticTokenUI");
			if (MetaManagerType != null)
			{
				MetaManagerInstanceField = AccessTools.Field(MetaManagerType, "instance");
				CosmeticTokensField = AccessTools.Field(MetaManagerType, "cosmeticTokens");
			}
			if (SemiFuncType != null)
			{
				RunIsShopMethod = AccessTools.Method(SemiFuncType, "RunIsShop", (Type[])null, (Type[])null);
			}
			if (RunManagerType != null)
			{
				RunManagerInstanceField = AccessTools.Field(RunManagerType, "instance");
			}
			if (GameDirectorType != null)
			{
				GameDirectorInstanceField = AccessTools.Field(GameDirectorType, "instance");
				GameDirectorCurrentStateField = AccessTools.Field(GameDirectorType, "currentState");
			}
			if (MetaManagerType == null)
			{
				Log.LogWarning((object)"Failure: MetaManager type was not found. HUD will stay hidden.");
			}
			if (CosmeticTokensField == null)
			{
				Log.LogWarning((object)"Failure: cosmeticTokens field was not found. HUD will stay hidden.");
			}
		}

		private void ApplyPatches()
		{
			TryPatchPostfix(MetaManagerType, "CosmeticTokenAdd", "MetaManager_CosmeticTokenAdd_Postfix");
			TryPatchPostfix(MetaManagerType, "CosmeticTokenRemove", "MetaManager_CosmeticTokenRemove_Postfix");
			TryPatchPostfix(ShopManagerType, "ShopInitialize", "ShopManager_ShopInitialize_Postfix");
			TryPatchPostfix(CosmeticShopMachineType, "Interact", "CosmeticShopMachine_Interact_Postfix");
			TryPatchPostfix(CosmeticShopMachineType, "RewardSet", "CosmeticShopMachine_RewardSet_Postfix");
			TryPatchPostfix(CosmeticTokenUIType, "Setup", "CosmeticTokenUI_Setup_Postfix");
		}

		private void TryPatchPostfix(Type targetType, string targetMethodName, string postfixMethodName)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			try
			{
				if (targetType == null)
				{
					WriteDebugLog("Patch skipped because target type is missing: " + targetMethodName);
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(targetType, targetMethodName, (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(CosmeticTokenCountHUDPlugin), postfixMethodName, (Type[])null, (Type[])null);
				if (methodInfo == null || methodInfo2 == null)
				{
					WriteDebugLog("Patch skipped: " + targetType.Name + "." + targetMethodName);
					return;
				}
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				WriteDebugLog("Patch applied: " + targetType.Name + "." + targetMethodName);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Failure: TryPatchPostfix " + targetMethodName + "\n" + ex));
			}
		}

		private static void MetaManager_CosmeticTokenAdd_Postfix()
		{
			RequestRefresh("CosmeticTokenAdd");
		}

		private static void MetaManager_CosmeticTokenRemove_Postfix()
		{
			RequestRefresh("CosmeticTokenRemove");
		}

		private static void ShopManager_ShopInitialize_Postfix()
		{
			RequestRefresh("ShopInitialize");
		}

		private static void CosmeticShopMachine_Interact_Postfix()
		{
			if (RefreshOnCosmeticShopMachineInteract != null && RefreshOnCosmeticShopMachineInteract.Value)
			{
				RequestRefresh("CosmeticShopMachine.Interact");
			}
		}

		private static void CosmeticShopMachine_RewardSet_Postfix()
		{
			RequestRefresh("CosmeticShopMachine.RewardSet");
		}

		private static void CosmeticTokenUI_Setup_Postfix()
		{
			if (RefreshOnCosmeticTokenUISetup != null && RefreshOnCosmeticTokenUISetup.Value)
			{
				RequestRefresh("CosmeticTokenUI.Setup");
			}
		}

		internal static List<int> GetCosmeticTokens()
		{
			try
			{
				object metaManagerInstance = GetMetaManagerInstance();
				if (metaManagerInstance == null || CosmeticTokensField == null)
				{
					return null;
				}
				return CosmeticTokensField.GetValue(metaManagerInstance) as List<int>;
			}
			catch (Exception ex)
			{
				WriteDebugLog("Failure: GetCosmeticTokens\n" + ex);
				return null;
			}
		}

		internal static object GetMetaManagerInstance()
		{
			try
			{
				if (MetaManagerInstanceField == null)
				{
					return null;
				}
				return MetaManagerInstanceField.GetValue(null);
			}
			catch (Exception ex)
			{
				WriteDebugLog("Failure: GetMetaManagerInstance\n" + ex);
				return null;
			}
		}

		internal static bool IsSafeShopState()
		{
			try
			{
				if (RunManagerInstanceField == null || GameDirectorInstanceField == null || GameDirectorCurrentStateField == null || RunIsShopMethod == null)
				{
					return false;
				}
				object value = RunManagerInstanceField.GetValue(null);
				object value2 = GameDirectorInstanceField.GetValue(null);
				if (value == null || value2 == null)
				{
					return false;
				}
				object value3 = GameDirectorCurrentStateField.GetValue(value2);
				if (value3 == null || !string.Equals(value3.ToString(), "Main", StringComparison.OrdinalIgnoreCase))
				{
					return false;
				}
				object obj = RunIsShopMethod.Invoke(null, null);
				return obj is bool && (bool)obj;
			}
			catch (Exception ex)
			{
				WriteDebugLog("Failure: IsSafeShopState\n" + ex);
				return false;
			}
		}

		internal static void RequestRefresh(string reason)
		{
			PendingRefresh = true;
			CosmeticTokenCountHUDController instance = CosmeticTokenCountHUDController.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.RequestImmediateRefresh(reason);
			}
		}

		internal static void WriteDebugLog(string message)
		{
			if (ShowDebugLog != null && ShowDebugLog.Value && Log != null)
			{
				Log.LogInfo((object)message);
			}
		}
	}
	internal class CosmeticTokenCountHUDController : MonoBehaviour
	{
		internal static CosmeticTokenCountHUDController Instance;

		private GameObject hudRoot;

		private Canvas hudCanvas;

		private RectTransform panelTransform;

		private Image backgroundImage;

		private Text titleText;

		private readonly List<Text> rarityTexts = new List<Text>();

		private Font cachedFont;

		private float refreshTimer;

		private bool forceRefresh;

		private string lastSignature = string.Empty;

		private void Awake()
		{
			Instance = this;
		}

		private void OnDestroy()
		{
			DestroyHud("controller destroyed");
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			try
			{
				if (CosmeticTokenCountHUDPlugin.Enable == null || !CosmeticTokenCountHUDPlugin.Enable.Value)
				{
					DestroyHud("disabled");
					return;
				}
				if (CosmeticTokenCountHUDPlugin.PendingRefresh)
				{
					CosmeticTokenCountHUDPlugin.PendingRefresh = false;
					forceRefresh = true;
				}
				if (forceRefresh)
				{
					forceRefresh = false;
					refreshTimer = GetRefreshInterval();
					RefreshHud();
					return;
				}
				refreshTimer -= Time.deltaTime;
				if (refreshTimer <= 0f)
				{
					refreshTimer = GetRefreshInterval();
					RefreshHud();
				}
			}
			catch (Exception ex)
			{
				CosmeticTokenCountHUDPlugin.WriteDebugLog("Failure: Update\n" + ex);
				DestroyHud("update failure");
			}
		}

		internal void RequestImmediateRefresh(string reason)
		{
			forceRefresh = true;
			CosmeticTokenCountHUDPlugin.WriteDebugLog("Refresh requested: " + reason);
		}

		private void RefreshHud()
		{
			if (!ShouldDisplayHud())
			{
				DestroyHud("display condition not met");
				return;
			}
			List<int> cosmeticTokens = CosmeticTokenCountHUDPlugin.GetCosmeticTokens();
			if (cosmeticTokens == null)
			{
				DestroyHud("token list missing");
				return;
			}
			TokenCounts counts = CountTokens(cosmeticTokens);
			if (CosmeticTokenCountHUDPlugin.HideWhenNoToken.Value && counts.TotalValid <= 0)
			{
				DestroyHud("no token");
				return;
			}
			EnsureHudExists();
			if (!((Object)(object)hudRoot == (Object)null))
			{
				ApplyHud(counts);
			}
		}

		private bool ShouldDisplayHud()
		{
			if (CosmeticTokenCountHUDPlugin.GetMetaManagerInstance() == null)
			{
				return false;
			}
			if (CosmeticTokenCountHUDPlugin.ShowOnlyInShop.Value && !CosmeticTokenCountHUDPlugin.IsSafeShopState())
			{
				return false;
			}
			return true;
		}

		private TokenCounts CountTokens(List<int> tokens)
		{
			TokenCounts result = default(TokenCounts);
			for (int i = 0; i < tokens.Count; i++)
			{
				switch (tokens[i])
				{
				case 0:
					result.Common++;
					result.TotalValid++;
					break;
				case 1:
					result.Uncommon++;
					result.TotalValid++;
					break;
				case 2:
					result.Rare++;
					result.TotalValid++;
					break;
				case 3:
					result.UltraRare++;
					result.TotalValid++;
					break;
				default:
					result.Invalid++;
					break;
				}
			}
			if (result.Invalid > 0)
			{
				CosmeticTokenCountHUDPlugin.WriteDebugLog("Invalid cosmetic token rarity count: " + result.Invalid);
			}
			return result;
		}

		private void EnsureHudExists()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			if ((Object)(object)hudRoot != (Object)null)
			{
				return;
			}
			try
			{
				hudRoot = new GameObject("CosmeticTokenCountHUD_Canvas");
				hudCanvas = hudRoot.AddComponent<Canvas>();
				hudCanvas.renderMode = (RenderMode)0;
				hudCanvas.sortingOrder = CosmeticTokenCountHUDPlugin.SortingOrder.Value;
				CanvasScaler val = hudRoot.AddComponent<CanvasScaler>();
				val.uiScaleMode = (ScaleMode)1;
				val.referenceResolution = new Vector2(1920f, 1080f);
				val.screenMatchMode = (ScreenMatchMode)0;
				val.matchWidthOrHeight = 0.5f;
				GameObject val2 = new GameObject("Panel");
				val2.transform.SetParent(hudRoot.transform, false);
				panelTransform = val2.AddComponent<RectTransform>();
				backgroundImage = val2.AddComponent<Image>();
				((Graphic)backgroundImage).raycastTarget = false;
				titleText = CreateText("Title", (Transform)(object)panelTransform, isTitle: true);
				rarityTexts.Clear();
				rarityTexts.Add(CreateText("Common", (Transform)(object)panelTransform, isTitle: false));
				rarityTexts.Add(CreateText("Uncommon", (Transform)(object)panelTransform, isTitle: false));
				rarityTexts.Add(CreateText("Rare", (Transform)(object)panelTransform, isTitle: false));
				rarityTexts.Add(CreateText("UltraRare", (Transform)(object)panelTransform, isTitle: false));
				CosmeticTokenCountHUDPlugin.WriteDebugLog("HUD created");
			}
			catch (Exception ex)
			{
				CosmeticTokenCountHUDPlugin.WriteDebugLog("Failure: EnsureHudExists\n" + ex);
				DestroyHud("create failure");
			}
		}

		private Text CreateText(string objectName, Transform parent, bool isTitle)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(objectName);
			val.transform.SetParent(parent, false);
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchorMin = new Vector2(0f, 1f);
			val2.anchorMax = new Vector2(0f, 1f);
			val2.pivot = new Vector2(0f, 1f);
			Text val3 = val.AddComponent<Text>();
			val3.font = GetFont();
			val3.fontSize = CosmeticTokenCountHUDPlugin.FontSize.Value;
			val3.fontStyle = (FontStyle)(isTitle ? 1 : 0);
			val3.alignment = GetTextAnchor();
			val3.horizontalOverflow = (HorizontalWrapMode)1;
			val3.verticalOverflow = (VerticalWrapMode)1;
			((Graphic)val3).raycastTarget = false;
			((Graphic)val3).color = GetTextColor("#FFFFFF");
			return val3;
		}

		private Font GetFont()
		{
			if ((Object)(object)cachedFont == (Object)null)
			{
				cachedFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
			}
			return cachedFont;
		}

		private void ApplyHud(TokenCounts counts)
		{
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			string text = BuildSignature(counts);
			if (text == lastSignature)
			{
				return;
			}
			lastSignature = text;
			if ((Object)(object)hudCanvas != (Object)null)
			{
				hudCanvas.sortingOrder = CosmeticTokenCountHUDPlugin.SortingOrder.Value;
			}
			List<RarityLine> list = BuildRarityLines(counts);
			int num = Mathf.Clamp(CosmeticTokenCountHUDPlugin.FontSize.Value, 8, 48);
			float num2 = Mathf.Clamp(CosmeticTokenCountHUDPlugin.PaddingX.Value, 0f, 60f);
			float num3 = Mathf.Clamp(CosmeticTokenCountHUDPlugin.PaddingY.Value, 0f, 60f);
			float num4 = Mathf.Clamp(CosmeticTokenCountHUDPlugin.LineSpacing.Value, 0f, 24f);
			float num5 = (float)num + 6f;
			int num6 = 1 + list.Count;
			float num7 = Mathf.Clamp(CosmeticTokenCountHUDPlugin.Width.Value, 120f, 800f);
			if (CosmeticTokenCountHUDPlugin.AutoResizeWidth.Value)
			{
				int maxTextLength = GetMaxTextLength(list);
				float num8 = (float)maxTextLength * (float)num * 0.62f + num2 * 2f;
				num7 = Mathf.Clamp(Mathf.Max(num7, num8), 120f, 1000f);
			}
			float height = num3 * 2f + (float)num6 * num5 + (float)Mathf.Max(0, num6 - 1) * num4;
			ApplyPanelTransform(num7, height);
			if ((Object)(object)backgroundImage != (Object)null)
			{
				((Graphic)backgroundImage).color = GetBackgroundColor();
			}
			ApplyTextTransform(titleText, CosmeticTokenCountHUDPlugin.TitleText.Value, GetTextColor("#FFFFFF"), num2, num3, num7, num5, num, 0);
			for (int i = 0; i < rarityTexts.Count; i++)
			{
				if (i < list.Count)
				{
					((Component)rarityTexts[i]).gameObject.SetActive(true);
					ApplyTextTransform(rarityTexts[i], list[i].Text, list[i].Color, num2, num3, num7, num5, num, i + 1);
				}
				else
				{
					((Component)rarityTexts[i]).gameObject.SetActive(false);
				}
			}
			CosmeticTokenCountHUDPlugin.WriteDebugLog("HUD refreshed: Common=" + counts.Common + ", Uncommon=" + counts.Uncommon + ", Rare=" + counts.Rare + ", UltraRare=" + counts.UltraRare);
		}

		private void ApplyPanelTransform(float width, float height)
		{
			//IL_0041: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)panelTransform == (Object)null))
			{
				switch (CosmeticTokenCountHUDPlugin.Anchor.Value)
				{
				case HudAnchor.TopLeft:
					panelTransform.anchorMin = new Vector2(0f, 1f);
					panelTransform.anchorMax = new Vector2(0f, 1f);
					panelTransform.pivot = new Vector2(0f, 1f);
					break;
				case HudAnchor.TopRight:
					panelTransform.anchorMin = new Vector2(1f, 1f);
					panelTransform.anchorMax = new Vector2(1f, 1f);
					panelTransform.pivot = new Vector2(1f, 1f);
					break;
				case HudAnchor.BottomLeft:
					panelTransform.anchorMin = new Vector2(0f, 0f);
					panelTransform.anchorMax = new Vector2(0f, 0f);
					panelTransform.pivot = new Vector2(0f, 0f);
					break;
				default:
					panelTransform.anchorMin = new Vector2(1f, 0f);
					panelTransform.anchorMax = new Vector2(1f, 0f);
					panelTransform.pivot = new Vector2(1f, 0f);
					break;
				}
				panelTransform.sizeDelta = new Vector2(width, height);
				panelTransform.anchoredPosition = new Vector2(CosmeticTokenCountHUDPlugin.OffsetX.Value, CosmeticTokenCountHUDPlugin.OffsetY.Value);
			}
		}

		private void ApplyTextTransform(Text text, string value, Color color, float paddingX, float paddingY, float width, float lineHeight, int fontSize, int index)
		{
			//IL_0012: 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_0047: 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)
			if (!((Object)(object)text == (Object)null))
			{
				text.text = value;
				((Graphic)text).color = color;
				text.fontSize = fontSize;
				text.alignment = GetTextAnchor();
				RectTransform component = ((Component)text).GetComponent<RectTransform>();
				component.sizeDelta = new Vector2(width - paddingX * 2f, lineHeight + 2f);
				component.anchoredPosition = new Vector2(paddingX, 0f - paddingY - (float)index * (lineHeight + CosmeticTokenCountHUDPlugin.LineSpacing.Value));
			}
		}

		private List<RarityLine> BuildRarityLines(TokenCounts counts)
		{
			//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_005e: Unknown result type (might be due to invalid IL or missing references)
			List<int> displayOrder = GetDisplayOrder();
			List<RarityLine> list = new List<RarityLine>();
			for (int i = 0; i < displayOrder.Count; i++)
			{
				int rarity = displayOrder[i];
				int countByRarity = GetCountByRarity(counts, rarity);
				if (CosmeticTokenCountHUDPlugin.ShowZeroCountRarity.Value || countByRarity > 0)
				{
					string labelByRarity = GetLabelByRarity(rarity);
					string text = labelByRarity + ": " + countByRarity;
					Color colorByRarity = GetColorByRarity(rarity);
					list.Add(new RarityLine(text, colorByRarity));
				}
			}
			return list;
		}

		private List<int> GetDisplayOrder()
		{
			List<int> list = new List<int>();
			switch (CosmeticTokenCountHUDPlugin.DisplayOrder.Value)
			{
			case DisplayOrderMode.HighToLow:
				list.Add(3);
				list.Add(2);
				list.Add(1);
				list.Add(0);
				break;
			case DisplayOrderMode.Custom:
				list = ParseCustomDisplayOrder();
				break;
			default:
				list.Add(0);
				list.Add(1);
				list.Add(2);
				list.Add(3);
				break;
			}
			if (list.Count == 0)
			{
				list.Add(0);
				list.Add(1);
				list.Add(2);
				list.Add(3);
			}
			return list;
		}

		private List<int> ParseCustomDisplayOrder()
		{
			List<int> list = new List<int>();
			string value = CosmeticTokenCountHUDPlugin.CustomDisplayOrder.Value;
			if (string.IsNullOrEmpty(value))
			{
				return list;
			}
			string[] array = value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				int num = ParseRarityName(array[i].Trim());
				if (num >= 0 && !list.Contains(num))
				{
					list.Add(num);
				}
			}
			return list;
		}

		private int ParseRarityName(string value)
		{
			if (string.Equals(value, "Common", StringComparison.OrdinalIgnoreCase))
			{
				return 0;
			}
			if (string.Equals(value, "Uncommon", StringComparison.OrdinalIgnoreCase))
			{
				return 1;
			}
			if (string.Equals(value, "Rare", StringComparison.OrdinalIgnoreCase))
			{
				return 2;
			}
			if (string.Equals(value, "UltraRare", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "Ultra Rare", StringComparison.OrdinalIgnoreCase))
			{
				return 3;
			}
			return -1;
		}

		private int GetCountByRarity(TokenCounts counts, int rarity)
		{
			return rarity switch
			{
				0 => counts.Common, 
				1 => counts.Uncommon, 
				2 => counts.Rare, 
				3 => counts.UltraRare, 
				_ => 0, 
			};
		}

		private string GetLabelByRarity(int rarity)
		{
			return rarity switch
			{
				0 => CosmeticTokenCountHUDPlugin.CommonLabel.Value, 
				1 => CosmeticTokenCountHUDPlugin.UncommonLabel.Value, 
				2 => CosmeticTokenCountHUDPlugin.RareLabel.Value, 
				3 => CosmeticTokenCountHUDPlugin.UltraRareLabel.Value, 
				_ => "Unknown", 
			};
		}

		private Color GetColorByRarity(int rarity)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_006e: 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)
			if (!CosmeticTokenCountHUDPlugin.UseRarityTextColor.Value)
			{
				return GetTextColor("#FFFFFF");
			}
			return (Color)(rarity switch
			{
				0 => GetTextColor(CosmeticTokenCountHUDPlugin.CommonColor.Value), 
				1 => GetTextColor(CosmeticTokenCountHUDPlugin.UncommonColor.Value), 
				2 => GetTextColor(CosmeticTokenCountHUDPlugin.RareColor.Value), 
				3 => GetTextColor(CosmeticTokenCountHUDPlugin.UltraRareColor.Value), 
				_ => GetTextColor("#FFFFFF"), 
			});
		}

		private Color GetTextColor(string hex)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Color result = ParseColor(hex, Color.white);
			result.a = Mathf.Clamp(CosmeticTokenCountHUDPlugin.TextOpacity.Value, 0.1f, 1f);
			return result;
		}

		private Color GetBackgroundColor()
		{
			//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)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Color result = ParseColor(CosmeticTokenCountHUDPlugin.BackgroundColor.Value, Color.black);
			result.a = Mathf.Clamp01(CosmeticTokenCountHUDPlugin.BackgroundOpacity.Value);
			return result;
		}

		private Color ParseColor(string hex, Color fallback)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(hex))
			{
				return fallback;
			}
			string text = hex.Trim();
			if (!text.StartsWith("#"))
			{
				text = "#" + text;
			}
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(text, ref result))
			{
				return result;
			}
			return fallback;
		}

		private TextAnchor GetTextAnchor()
		{
			return (TextAnchor)(CosmeticTokenCountHUDPlugin.TextAlign.Value switch
			{
				HudTextAlign.Center => 1, 
				HudTextAlign.Right => 2, 
				_ => 0, 
			});
		}

		private int GetMaxTextLength(List<RarityLine> lines)
		{
			int num = 0;
			if (!string.IsNullOrEmpty(CosmeticTokenCountHUDPlugin.TitleText.Value))
			{
				num = CosmeticTokenCountHUDPlugin.TitleText.Value.Length;
			}
			for (int i = 0; i < lines.Count; i++)
			{
				if (!string.IsNullOrEmpty(lines[i].Text) && lines[i].Text.Length > num)
				{
					num = lines[i].Text.Length;
				}
			}
			return num;
		}

		private string BuildSignature(TokenCounts counts)
		{
			return counts.Common + "|" + counts.Uncommon + "|" + counts.Rare + "|" + counts.UltraRare + "|" + CosmeticTokenCountHUDPlugin.ShowZeroCountRarity.Value + "|" + CosmeticTokenCountHUDPlugin.Anchor.Value.ToString() + "|" + CosmeticTokenCountHUDPlugin.OffsetX.Value + "|" + CosmeticTokenCountHUDPlugin.OffsetY.Value + "|" + CosmeticTokenCountHUDPlugin.FontSize.Value + "|" + CosmeticTokenCountHUDPlugin.BackgroundOpacity.Value + "|" + CosmeticTokenCountHUDPlugin.TextOpacity.Value + "|" + CosmeticTokenCountHUDPlugin.SortingOrder.Value + "|" + CosmeticTokenCountHUDPlugin.LineSpacing.Value + "|" + CosmeticTokenCountHUDPlugin.PaddingX.Value + "|" + CosmeticTokenCountHUDPlugin.PaddingY.Value + "|" + CosmeticTokenCountHUDPlugin.Width.Value + "|" + CosmeticTokenCountHUDPlugin.AutoResizeWidth.Value + "|" + CosmeticTokenCountHUDPlugin.TextAlign.Value.ToString() + "|" + CosmeticTokenCountHUDPlugin.DisplayOrder.Value.ToString() + "|" + CosmeticTokenCountHUDPlugin.CustomDisplayOrder.Value + "|" + CosmeticTokenCountHUDPlugin.TitleText.Value + "|" + CosmeticTokenCountHUDPlugin.CommonLabel.Value + "|" + CosmeticTokenCountHUDPlugin.UncommonLabel.Value + "|" + CosmeticTokenCountHUDPlugin.RareLabel.Value + "|" + CosmeticTokenCountHUDPlugin.UltraRareLabel.Value + "|" + CosmeticTokenCountHUDPlugin.UseRarityTextColor.Value + "|" + CosmeticTokenCountHUDPlugin.CommonColor.Value + "|" + CosmeticTokenCountHUDPlugin.UncommonColor.Value + "|" + CosmeticTokenCountHUDPlugin.RareColor.Value + "|" + CosmeticTokenCountHUDPlugin.UltraRareColor.Value + "|" + CosmeticTokenCountHUDPlugin.BackgroundColor.Value;
		}

		private float GetRefreshInterval()
		{
			if (CosmeticTokenCountHUDPlugin.RefreshIntervalSeconds == null)
			{
				return 0.35f;
			}
			return Mathf.Clamp(CosmeticTokenCountHUDPlugin.RefreshIntervalSeconds.Value, 0.1f, 2f);
		}

		private void DestroyHud(string reason)
		{
			if ((Object)(object)hudRoot != (Object)null)
			{
				Object.Destroy((Object)(object)hudRoot);
				hudRoot = null;
				hudCanvas = null;
				panelTransform = null;
				backgroundImage = null;
				titleText = null;
				rarityTexts.Clear();
				lastSignature = string.Empty;
				CosmeticTokenCountHUDPlugin.WriteDebugLog("HUD destroyed: " + reason);
			}
		}
	}
	internal struct TokenCounts
	{
		internal int Common;

		internal int Uncommon;

		internal int Rare;

		internal int UltraRare;

		internal int TotalValid;

		internal int Invalid;
	}
	internal struct RarityLine
	{
		internal readonly string Text;

		internal readonly Color Color;

		internal RarityLine(string text, Color color)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Text = text;
			Color = color;
		}
	}
	public enum HudAnchor
	{
		TopLeft,
		TopRight,
		BottomLeft,
		BottomRight
	}
	public enum HudTextAlign
	{
		Left,
		Center,
		Right
	}
	public enum DisplayOrderMode
	{
		LowToHigh,
		HighToLow,
		Vanilla,
		Custom
	}
}