Decompiled source of ItemBrowser v0.2.4

plugins/com.github.cherrycove.ItemBrowser.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
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 Newtonsoft.Json;
using PEAKLib.UI;
using PEAKLib.UI.Elements;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Zorro.Core;
using Zorro.Core.CLI;
using Zorro.Settings;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.cherrycove.ItemBrowser")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.4.0")]
[assembly: AssemblyInformationalVersion("0.2.4+d197c5ba1ea75398d80ea31a27f4cc560ba8366d")]
[assembly: AssemblyProduct("com.github.cherrycove.ItemBrowser")]
[assembly: AssemblyTitle("ItemBrowser")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.4.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.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]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace ItemBrowser
{
	internal static class CategorySystem
	{
		private sealed class WikiCategoryGroup
		{
			internal ItemCategory Category { get; }

			internal string[] Names { get; }

			internal WikiCategoryGroup(ItemCategory category, string[] names)
			{
				Category = category;
				Names = names;
			}
		}

		[CompilerGenerated]
		private sealed class <GetCategoryCandidateKeys>d__8 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private string <>2__current;

			private int <>l__initialThreadId;

			private Item item;

			public Item <>3__item;

			private string displayName;

			public string <>3__displayName;

			private string <prefabName>5__2;

			string IEnumerator<string>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <GetCategoryCandidateKeys>d__8(int <>1__state)
			{
				this.<>1__state = <>1__state;
				<>l__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<prefabName>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<prefabName>5__2 = ((Object)item).name ?? string.Empty;
					if (!string.IsNullOrWhiteSpace(<prefabName>5__2))
					{
						<>2__current = NormalizeCategoryKey(<prefabName>5__2);
						<>1__state = 1;
						return true;
					}
					goto IL_00ac;
				case 1:
				{
					<>1__state = -1;
					int num = <prefabName>5__2.IndexOf(" Variant", StringComparison.OrdinalIgnoreCase);
					if (num > 0)
					{
						<>2__current = NormalizeCategoryKey(<prefabName>5__2.Substring(0, num));
						<>1__state = 2;
						return true;
					}
					goto IL_00ac;
				}
				case 2:
					<>1__state = -1;
					goto IL_00ac;
				case 3:
					{
						<>1__state = -1;
						break;
					}
					IL_00ac:
					if (!string.IsNullOrWhiteSpace(displayName))
					{
						<>2__current = NormalizeCategoryKey(displayName);
						<>1__state = 3;
						return true;
					}
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<string> IEnumerable<string>.GetEnumerator()
			{
				<GetCategoryCandidateKeys>d__8 <GetCategoryCandidateKeys>d__;
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					<GetCategoryCandidateKeys>d__ = this;
				}
				else
				{
					<GetCategoryCandidateKeys>d__ = new <GetCategoryCandidateKeys>d__8(0);
				}
				<GetCategoryCandidateKeys>d__.item = <>3__item;
				<GetCategoryCandidateKeys>d__.displayName = <>3__displayName;
				return <GetCategoryCandidateKeys>d__;
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<string>)this).GetEnumerator();
			}
		}

		private static readonly WikiCategoryGroup[] _wikiCategoryGroups = BuildWikiCategoryGroups();

		private static readonly Dictionary<string, ItemCategory> _wikiOverrides = BuildWikiCategoryOverrides();

		private static readonly Dictionary<string, int> _wikiOrder = BuildWikiCategoryOrder();

		private static readonly HashSet<string> _hiddenPrefabNames = BuildHiddenPrefabNameSet();

		internal static bool ShouldHideItemFromBrowser(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return true;
			}
			string text = ((Object)item).name ?? string.Empty;
			if (string.IsNullOrWhiteSpace(text))
			{
				return true;
			}
			string item2 = NormalizeCategoryKey(text);
			if (_hiddenPrefabNames.Contains(item2))
			{
				return true;
			}
			if (text.StartsWith("C_", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (text.Contains("_Prop", StringComparison.OrdinalIgnoreCase) || text.Contains("_TEMP", StringComparison.OrdinalIgnoreCase) || text.Contains("_UNUSED", StringComparison.OrdinalIgnoreCase) || text.Contains("_Hidden", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return false;
		}

		private static HashSet<string> BuildHiddenPrefabNameSet()
		{
			return new HashSet<string>(StringComparer.OrdinalIgnoreCase)
			{
				NormalizeCategoryKey("Lollipop_Prop"),
				NormalizeCategoryKey("Lollipop_Prop Variant"),
				NormalizeCategoryKey("FortifiedMilk_TEMP"),
				NormalizeCategoryKey("Clusterberry_UNUSED"),
				NormalizeCategoryKey("Mandrake_Hidden"),
				NormalizeCategoryKey("BingBong_Prop Variant"),
				NormalizeCategoryKey("Binoculars_Prop"),
				NormalizeCategoryKey("Bugle_Prop Variant"),
				NormalizeCategoryKey("Berrynana Peel Blue Variant"),
				NormalizeCategoryKey("Berrynana Peel Brown Variant"),
				NormalizeCategoryKey("Berrynana Peel Pink Variant"),
				NormalizeCategoryKey("Berrynana Peel Yellow"),
				NormalizeCategoryKey("GuidebookPage_4_BodyHeat Variant"),
				NormalizeCategoryKey("GuidebookPage_5_Sleepy Variant"),
				NormalizeCategoryKey("GuidebookPage_6_Awake Variant"),
				NormalizeCategoryKey("GuidebookPage_7_Crashout Variant"),
				NormalizeCategoryKey("Parasol_Roots Variant"),
				NormalizeCategoryKey("ClimbingChalk"),
				NormalizeCategoryKey("Skull")
			};
		}

		internal static ItemCategory GetCategory(Item item, string displayName)
		{
			if ((Object)(object)item == (Object)null)
			{
				return ItemCategory.MiscEquipment;
			}
			if (TryGetCategoryOverride(item, displayName, out var category))
			{
				return category;
			}
			WarnFallbackCategory(item, displayName);
			return ItemCategory.MiscEquipment;
		}

		private static bool TryGetCategoryOverride(Item item, string displayName, out ItemCategory category)
		{
			category = ItemCategory.NaturalFood;
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			List<string> list = (from x in GetCategoryCandidateKeys(item, displayName)
				where !string.IsNullOrWhiteSpace(x)
				select x).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList();
			for (int i = 0; i < list.Count; i++)
			{
				string text = list[i];
				if (_wikiOverrides.TryGetValue(text, out category))
				{
					Plugin.VerboseLog($"Category override hit: key='{text}' -> {category} (prefab='{((Object)item).name}', display='{displayName}')");
					return true;
				}
			}
			return false;
		}

		[IteratorStateMachine(typeof(<GetCategoryCandidateKeys>d__8))]
		private static IEnumerable<string> GetCategoryCandidateKeys(Item item, string displayName)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <GetCategoryCandidateKeys>d__8(-2)
			{
				<>3__item = item,
				<>3__displayName = displayName
			};
		}

		private static WikiCategoryGroup[] BuildWikiCategoryGroups()
		{
			return new WikiCategoryGroup[8]
			{
				new WikiCategoryGroup(ItemCategory.NaturalFood, new string[34]
				{
					"Item_Coconut", "Item_Coconut_half", "Apple Berry Red", "Apple Berry Yellow", "Apple Berry Green", "Item_Honeycomb", "Pepper Berry", "Kingberry Purple", "Kingberry Yellow", "Kingberry Green",
					"Berrynana Pink", "Berrynana Blue", "Berrynana Brown", "Clusterberry Yellow", "Clusterberry Red", "Clusterberry Black", "Winterberry Orange", "Winterberry Yellow", "Prickleberry_Red", "Prickleberry_Gold",
					"MedicinalRoot", "Mandrake", "Marshmallow", "Glizzy", "Egg", "EggTurkey", "Bugfix", "Scorpion", "Napberry", "Shroomberry_Red",
					"Shroomberry_Yellow", "Shroomberry_Green", "Shroomberry_Blue", "Shroomberry_Purple"
				}),
				new WikiCategoryGroup(ItemCategory.MysticalFood, new string[2] { "Cure-All", "PandorasBox" }),
				new WikiCategoryGroup(ItemCategory.PackagedFood, new string[8] { "Airplane Food", "Lollipop", "Energy Drink", "FortifiedMilk", "Granola Bar", "ScoutCookies", "Sports Drink", "TrailMix" }),
				new WikiCategoryGroup(ItemCategory.Mushroom, new string[7] { "Mushroom Lace", "Mushroom Lace Poison", "Mushroom Normie", "Mushroom Normie Poison", "Mushroom Chubby", "Mushroom Cluster", "Mushroom Cluster Poison" }),
				new WikiCategoryGroup(ItemCategory.Consumable, new string[12]
				{
					"Antidote", "Balloon", "BalloonBunch", "Bandages", "HealingDart Variant", "FirstAidKit", "Flare", "Heat Pack", "HealingPuffShroom", "RescueHook",
					"GuidebookPageScroll Variant", "Sunscreen"
				}),
				new WikiCategoryGroup(ItemCategory.Deployable, new string[11]
				{
					"BounceShroom", "ChainShooter", "Flag_Plantable_Checkpoint", "CloudFungus", "MagicBean", "ClimbingSpike", "PortableStovetopItem", "RopeShooter", "RopeSpool", "ScoutCannonItem",
					"ShelfShroom"
				}),
				new WikiCategoryGroup(ItemCategory.MiscEquipment, new string[11]
				{
					"Backpack", "BingBong", "Binoculars", "Bugle", "Compass", "Frisbee", "Guidebook", "Lantern", "Parasol", "Pirate Compass",
					"Torch"
				}),
				new WikiCategoryGroup(ItemCategory.MysticalItem, new string[9] { "AncientIdol", "RopeShooterAnti", "Anti-Rope Spool", "Bugle_Magic", "Cursed Skull", "Lantern_Faerie", "ScoutEffigy", "Bugle_Scoutmaster Variant", "BookOfBones" })
			};
		}

		private static Dictionary<string, ItemCategory> BuildWikiCategoryOverrides()
		{
			Dictionary<string, ItemCategory> dictionary = new Dictionary<string, ItemCategory>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < _wikiCategoryGroups.Length; i++)
			{
				WikiCategoryGroup wikiCategoryGroup = _wikiCategoryGroups[i];
				AddWikiOverride(dictionary, wikiCategoryGroup.Category, wikiCategoryGroup.Names);
			}
			return dictionary;
		}

		private static Dictionary<string, int> BuildWikiCategoryOrder()
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			int order = 0;
			for (int i = 0; i < _wikiCategoryGroups.Length; i++)
			{
				AddWikiOrder(dictionary, ref order, _wikiCategoryGroups[i].Names);
			}
			return dictionary;
		}

		private static void AddWikiOverride(Dictionary<string, ItemCategory> map, ItemCategory category, params string[] names)
		{
			foreach (string value in names)
			{
				if (!string.IsNullOrWhiteSpace(value))
				{
					map[NormalizeCategoryKey(value)] = category;
				}
			}
		}

		private static void AddWikiOrder(Dictionary<string, int> map, ref int order, params string[] names)
		{
			foreach (string value in names)
			{
				if (!string.IsNullOrWhiteSpace(value))
				{
					map[NormalizeCategoryKey(value)] = order++;
				}
			}
		}

		private static string NormalizeCategoryKey(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return string.Empty;
			}
			List<char> list = new List<char>(value.Length);
			foreach (char c in value)
			{
				if (char.IsLetterOrDigit(c))
				{
					list.Add(char.ToLowerInvariant(c));
				}
			}
			return new string(list.ToArray());
		}

		internal static int GetCategoryOrder(ItemCategory category)
		{
			return category switch
			{
				ItemCategory.NaturalFood => 0, 
				ItemCategory.MysticalFood => 1, 
				ItemCategory.PackagedFood => 2, 
				ItemCategory.Mushroom => 3, 
				ItemCategory.Consumable => 4, 
				ItemCategory.Deployable => 5, 
				ItemCategory.MiscEquipment => 6, 
				ItemCategory.MysticalItem => 7, 
				_ => 8, 
			};
		}

		internal static bool IsFoodCategory(ItemCategory category)
		{
			if (category != 0 && category != ItemCategory.MysticalFood && category != ItemCategory.PackagedFood)
			{
				return category == ItemCategory.Mushroom;
			}
			return true;
		}

		internal static bool IsEntryInMajorCategory(ItemEntry entry, MajorCategory major)
		{
			if (major == MajorCategory.All)
			{
				return true;
			}
			bool flag = IsFoodCategory(entry.Category);
			if (major != MajorCategory.Food)
			{
				return !flag;
			}
			return flag;
		}

		internal static int GetWikiSortOrder(ItemEntry entry)
		{
			if (entry == null)
			{
				return int.MaxValue;
			}
			foreach (string categoryCandidateKey in GetCategoryCandidateKeys(entry.Prefab, entry.DisplayName))
			{
				if (_wikiOrder.TryGetValue(categoryCandidateKey, out var value))
				{
					return value;
				}
			}
			return int.MaxValue;
		}

		internal static ItemCategory[] GetSubCategories(MajorCategory major)
		{
			return major switch
			{
				MajorCategory.All => Array.Empty<ItemCategory>(), 
				MajorCategory.Food => new ItemCategory[4]
				{
					ItemCategory.NaturalFood,
					ItemCategory.MysticalFood,
					ItemCategory.PackagedFood,
					ItemCategory.Mushroom
				}, 
				_ => new ItemCategory[4]
				{
					ItemCategory.Consumable,
					ItemCategory.Deployable,
					ItemCategory.MiscEquipment,
					ItemCategory.MysticalItem
				}, 
			};
		}

		internal static string GetMajorCategoryLabel(MajorCategory category)
		{
			return category switch
			{
				MajorCategory.All => Localization.GetTextOrFallback("CATEGORY_ALL", "All"), 
				MajorCategory.Food => Localization.GetTextOrFallback("CATEGORY_FOOD", "Food"), 
				MajorCategory.Weapon => Localization.GetTextOrFallback("CATEGORY_WEAPON", "Weapon"), 
				_ => "Unknown", 
			};
		}

		internal static string GetCategoryLabel(ItemCategory category)
		{
			return category switch
			{
				ItemCategory.NaturalFood => Localization.GetTextOrFallback("CATEGORY_NATURAL_FOOD", "Natural Food"), 
				ItemCategory.MysticalFood => Localization.GetTextOrFallback("CATEGORY_MYSTICAL_FOOD", "Mystical Food"), 
				ItemCategory.PackagedFood => Localization.GetTextOrFallback("CATEGORY_PACKAGED_FOOD", "Packaged Food"), 
				ItemCategory.Mushroom => Localization.GetTextOrFallback("CATEGORY_MUSHROOM", "Mushroom"), 
				ItemCategory.Consumable => Localization.GetTextOrFallback("CATEGORY_CONSUMABLE", "Consumables"), 
				ItemCategory.Deployable => Localization.GetTextOrFallback("CATEGORY_DEPLOYABLE", "Deployable"), 
				ItemCategory.MiscEquipment => Localization.GetTextOrFallback("CATEGORY_MISC", "Misc"), 
				ItemCategory.MysticalItem => Localization.GetTextOrFallback("CATEGORY_MYSTICAL_ITEM", "Mystical Item"), 
				_ => "Other", 
			};
		}

		internal static string GetAllSubCategoryLabel()
		{
			return Localization.GetTextOrFallback("CATEGORY_ALL", "All");
		}

		private static void WarnFallbackCategory(Item item, string displayName)
		{
			Plugin.VerboseLog("Category fallback -> MiscEquipment. Prefab='" + (((item != null) ? ((Object)item).name : null) ?? "<null>") + "', Display='" + displayName + "'");
		}
	}
	internal static class IconResolver
	{
		[CompilerGenerated]
		private sealed class <WarmupMissingIconsGradually>d__9 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string reason;

			private int <budget>5__2;

			private int <i>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WarmupMissingIconsGradually>d__9(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<budget>5__2 = 1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<i>5__3 = 0;
					goto IL_00e7;
				case 2:
					{
						<>1__state = -1;
						goto IL_00d7;
					}
					IL_00e7:
					if (<i>5__3 < SharedState.ItemEntries.Count)
					{
						ItemEntry itemEntry = SharedState.ItemEntries[<i>5__3];
						_iconPrewarmProcessedCount++;
						if ((Object)(object)itemEntry.Icon == (Object)null)
						{
							Sprite itemIcon = GetItemIcon(itemEntry.Prefab);
							if ((Object)(object)itemIcon != (Object)null)
							{
								itemEntry.UpdateIcon(itemIcon);
								_iconPrewarmResolvedCount++;
							}
						}
						<budget>5__2--;
						if (<budget>5__2 <= 0)
						{
							<budget>5__2 = 1;
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						goto IL_00d7;
					}
					_iconPrewarmRunning = false;
					_iconPrewarmCoroutine = null;
					_iconPrewarmCompleted = true;
					Plugin.VerboseLog($"Icon prewarm completed ({reason}). Processed={_iconPrewarmProcessedCount}, Resolved={_iconPrewarmResolvedCount}");
					return false;
					IL_00d7:
					<i>5__3++;
					goto IL_00e7;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static Coroutine? _iconPrewarmCoroutine;

		private static bool _iconPrewarmRunning;

		private static bool _iconPrewarmCompleted;

		private static int _iconPrewarmProcessedCount;

		private static int _iconPrewarmResolvedCount;

		private static float _nextIconPrewarmCheckTime;

		internal static Sprite? ResolveEntryIcon(ItemEntry entry)
		{
			if ((Object)(object)entry.Icon != (Object)null)
			{
				return entry.Icon;
			}
			TryStartBackgroundIconPrewarm("VisibleEntryFallback");
			return null;
		}

		internal static void TickBackgroundIconPrewarm()
		{
			if (SharedState.ItemListInitialized && !SharedState.ItemPreloadRunning && !_iconPrewarmRunning && !_iconPrewarmCompleted && !SharedState.PageOpen && SharedState.ItemEntries.Count != 0 && !(Time.unscaledTime < _nextIconPrewarmCheckTime))
			{
				_nextIconPrewarmCheckTime = Time.unscaledTime + 0.15f;
				TryStartBackgroundIconPrewarm("AutoWarmup");
			}
		}

		internal static bool TryStartBackgroundIconPrewarm(string reason)
		{
			if (!SharedState.ItemListInitialized || SharedState.ItemPreloadRunning || _iconPrewarmRunning || _iconPrewarmCompleted)
			{
				return false;
			}
			if ((Object)(object)SharedState.Instance == (Object)null || SharedState.ItemEntries.Count == 0)
			{
				return false;
			}
			_iconPrewarmRunning = true;
			_iconPrewarmProcessedCount = 0;
			_iconPrewarmResolvedCount = 0;
			_iconPrewarmCoroutine = ((MonoBehaviour)SharedState.Instance).StartCoroutine(WarmupMissingIconsGradually(reason));
			Plugin.VerboseLog($"Icon prewarm started ({reason}). Entries={SharedState.ItemEntries.Count}");
			return true;
		}

		[IteratorStateMachine(typeof(<WarmupMissingIconsGradually>d__9))]
		private static IEnumerator WarmupMissingIconsGradually(string reason)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WarmupMissingIconsGradually>d__9(0)
			{
				reason = reason
			};
		}

		internal static void ResetIconPrewarmState(bool stopCoroutine)
		{
			if (stopCoroutine)
			{
				StopTrackedCoroutine(ref _iconPrewarmCoroutine);
			}
			else
			{
				_iconPrewarmCoroutine = null;
			}
			_iconPrewarmRunning = false;
			_iconPrewarmCompleted = false;
			_iconPrewarmProcessedCount = 0;
			_iconPrewarmResolvedCount = 0;
			_nextIconPrewarmCheckTime = 0f;
		}

		private static void StopTrackedCoroutine(ref Coroutine? coroutine)
		{
			if (coroutine != null)
			{
				if ((Object)(object)SharedState.Instance != (Object)null)
				{
					((MonoBehaviour)SharedState.Instance).StopCoroutine(coroutine);
				}
				coroutine = null;
			}
		}

		internal static Sprite? GetItemIcon(Item item, bool allowHeavyFallback = true)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			string key = ((Object)item).name ?? string.Empty;
			if (SharedState.ItemIconCache.TryGetValue(key, out Sprite value))
			{
				return value;
			}
			Sprite val = null;
			List<string> list = ((SharedState.ConfigVerboseLogs != null && SharedState.ConfigVerboseLogs.Value) ? new List<string>() : null);
			HashSet<int> visited = new HashSet<int>();
			try
			{
				val = TryExtractUiDataIcon(item, list);
				if ((Object)(object)val == (Object)null)
				{
					val = TryExtractSprite(item, list, "Item", 0, visited);
				}
				if ((Object)(object)val == (Object)null)
				{
					Component[] components = ((Component)item).GetComponents<Component>();
					for (int i = 0; i < components.Length; i++)
					{
						if (!((Object)(object)val == (Object)null))
						{
							break;
						}
						Component val2 = components[i];
						if (!((Object)(object)val2 == (Object)null))
						{
							val = TryExtractSprite(val2, list, ((object)val2).GetType().Name, 0, visited);
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					Image componentInChildren = ((Component)item).GetComponentInChildren<Image>(true);
					if ((Object)(object)componentInChildren != (Object)null)
					{
						val = componentInChildren.sprite;
						list?.Add(((Object)(object)val != (Object)null) ? ("UI.Image(sprite)=" + DescribeSprite(val)) : "UI.Image(sprite)=null");
					}
					else
					{
						list?.Add("UI.Image=missing");
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					SpriteRenderer componentInChildren2 = ((Component)item).GetComponentInChildren<SpriteRenderer>(true);
					if ((Object)(object)componentInChildren2 != (Object)null)
					{
						val = componentInChildren2.sprite;
						list?.Add(((Object)(object)val != (Object)null) ? ("SpriteRenderer(sprite)=" + DescribeSprite(val)) : "SpriteRenderer(sprite)=null");
					}
					else
					{
						list?.Add("SpriteRenderer=missing");
					}
				}
				if (allowHeavyFallback && (Object)(object)val == (Object)null)
				{
					val = TryExtractMaterialTextureSprite(item, list);
					if ((Object)(object)val == (Object)null)
					{
						list?.Add("HeavyFallback(material)=miss");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.VerboseLog("GetItemIcon failed for " + ((Object)item).name + ": " + ex.GetType().Name + " " + ex.Message);
			}
			if (list != null)
			{
				if ((Object)(object)val != (Object)null)
				{
					Plugin.VerboseLog("Icon resolved for '" + ((Object)item).name + "': " + DescribeSprite(val) + " | " + FormatProbe(list));
				}
				else
				{
					Plugin.Log.LogWarning((object)("[ItemBrowser] Icon missing for '" + ((Object)item).name + "'. Probe: " + FormatProbe(list)));
				}
			}
			SharedState.ItemIconCache[key] = val;
			return val;
		}

		private static Sprite? TryExtractUiDataIcon(Item item, List<string>? probe)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			try
			{
				ItemUIData uIData = item.UIData;
				Texture2D icon = uIData.icon;
				if ((Object)(object)icon != (Object)null)
				{
					return ConvertTextureToSprite(icon, "Item.UIData.icon", probe);
				}
				if (uIData.hasAltIcon && (Object)(object)uIData.altIcon != (Object)null)
				{
					return ConvertTextureToSprite(uIData.altIcon, "Item.UIData.altIcon", probe);
				}
				probe?.Add("Item.UIData.icon=null");
			}
			catch (Exception ex)
			{
				probe?.Add("Item.UIData=failed(" + ex.GetType().Name + ")");
			}
			return null;
		}

		private static Sprite? TryExtractSprite(object target, List<string>? probe = null, string? source = null, int depth = 0, HashSet<int>? visited = null)
		{
			if (target == null || depth > 2)
			{
				return null;
			}
			if (visited == null)
			{
				visited = new HashSet<int>();
			}
			if (!(target is string) && !target.GetType().IsValueType)
			{
				int hashCode = RuntimeHelpers.GetHashCode(target);
				if (!visited.Add(hashCode))
				{
					return null;
				}
			}
			string text = (string.IsNullOrWhiteSpace(source) ? target.GetType().Name : source);
			if (TryExtractSpriteFromValue(target, text, probe, depth, visited, out Sprite sprite))
			{
				return sprite;
			}
			Type type = target.GetType();
			string[] array = new string[18]
			{
				"Icon", "icon", "ItemIcon", "itemIcon", "IconSprite", "iconSprite", "Sprite", "sprite", "Thumbnail", "thumbnail",
				"Icons", "icons", "ItemIcons", "itemIcons", "Atlas", "atlas", "Texture", "texture"
			};
			foreach (string name in array)
			{
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					object value = null;
					try
					{
						value = field.GetValue(target);
					}
					catch
					{
					}
					if (TryExtractSpriteFromValue(value, text + "." + field.Name, probe, depth + 1, visited, out Sprite sprite2))
					{
						return sprite2;
					}
					probe?.Add(text + "." + field.Name + "<" + field.FieldType.Name + ">=" + DescribeProbeValue(value));
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanRead && property.GetIndexParameters().Length == 0)
				{
					object obj2 = null;
					try
					{
						obj2 = property.GetValue(target);
					}
					catch
					{
						obj2 = "<get_error>";
					}
					if (TryExtractSpriteFromValue(obj2, text + "." + property.Name, probe, depth + 1, visited, out Sprite sprite3))
					{
						return sprite3;
					}
					probe?.Add(text + "." + property.Name + "<" + property.PropertyType.Name + ">=" + DescribeProbeValue(obj2));
				}
			}
			FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (IsIconProbeMember(fieldInfo.Name, fieldInfo.FieldType))
				{
					object value2 = null;
					try
					{
						value2 = fieldInfo.GetValue(target);
					}
					catch
					{
					}
					if (TryExtractSpriteFromValue(value2, text + "." + fieldInfo.Name, probe, depth + 1, visited, out Sprite sprite4))
					{
						return sprite4;
					}
					probe?.Add(text + "." + fieldInfo.Name + "<" + fieldInfo.FieldType.Name + ">=" + DescribeProbeValue(value2));
				}
			}
			PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in properties)
			{
				if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0 && IsIconProbeMember(propertyInfo.Name, propertyInfo.PropertyType))
				{
					object obj5 = null;
					try
					{
						obj5 = propertyInfo.GetValue(target);
					}
					catch
					{
						obj5 = "<get_error>";
					}
					if (TryExtractSpriteFromValue(obj5, text + "." + propertyInfo.Name, probe, depth + 1, visited, out Sprite sprite5))
					{
						return sprite5;
					}
					probe?.Add(text + "." + propertyInfo.Name + "<" + propertyInfo.PropertyType.Name + ">=" + DescribeProbeValue(obj5));
				}
			}
			return null;
		}

		private static bool TryExtractSpriteFromValue(object? value, string source, List<string>? probe, int depth, HashSet<int> visited, out Sprite? sprite)
		{
			sprite = null;
			if (value == null)
			{
				return false;
			}
			Sprite val = (Sprite)((value is Sprite) ? value : null);
			if (val != null)
			{
				probe?.Add(source + "=" + DescribeSprite(val));
				sprite = val;
				return true;
			}
			Texture2D val2 = (Texture2D)((value is Texture2D) ? value : null);
			if (val2 != null)
			{
				sprite = ConvertTextureToSprite(val2, source, probe);
				return (Object)(object)sprite != (Object)null;
			}
			Texture val3 = (Texture)((value is Texture) ? value : null);
			if (val3 != null)
			{
				Texture2D val4 = (Texture2D)(object)((val3 is Texture2D) ? val3 : null);
				if (val4 != null)
				{
					sprite = ConvertTextureToSprite(val4, source, probe);
					return (Object)(object)sprite != (Object)null;
				}
				probe?.Add(source + "=texture('" + ((Object)val3).name + "') unsupported:" + ((object)val3).GetType().Name);
				return false;
			}
			if (value is IEnumerable enumerable && !(value is string) && ShouldEnumerateIconCollection(source, value))
			{
				int num = 0;
				foreach (object item in enumerable)
				{
					if (TryExtractSpriteFromValue(item, $"{source}[{num}]", probe, depth + 1, visited, out sprite))
					{
						return true;
					}
					num++;
					if (num >= 8)
					{
						break;
					}
				}
				return false;
			}
			if (depth >= 2)
			{
				return false;
			}
			Type type = value.GetType();
			if (type.IsPrimitive || type.IsEnum || value is string || value is decimal)
			{
				return false;
			}
			if (!ShouldDeepProbeSource(source, type))
			{
				return false;
			}
			sprite = TryExtractSprite(value, probe, source, depth + 1, visited);
			return (Object)(object)sprite != (Object)null;
		}

		private static Sprite? ConvertTextureToSprite(Texture2D texture, string source, List<string>? probe)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)texture == (Object)null)
			{
				return null;
			}
			int instanceID = ((Object)texture).GetInstanceID();
			if (SharedState.GeneratedTextureSpriteCache.TryGetValue(instanceID, out Sprite value) && (Object)(object)value != (Object)null)
			{
				probe?.Add(source + "=cached:" + DescribeSprite(value));
				return value;
			}
			if (((Texture)texture).width <= 0 || ((Texture)texture).height <= 0)
			{
				probe?.Add(source + "=texture('" + ((Object)texture).name + "') invalid_size");
				return null;
			}
			try
			{
				Sprite val = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
				((Object)val).name = ((Object)texture).name + "_AutoIcon";
				SharedState.GeneratedTextureSpriteCache[instanceID] = val;
				probe?.Add(source + "=texture->sprite:" + DescribeSprite(val));
				return val;
			}
			catch (Exception ex)
			{
				probe?.Add(source + "=texture_convert_failed(" + ex.GetType().Name + ")");
				return null;
			}
		}

		private static Sprite? TryExtractMaterialTextureSprite(Item item, List<string>? probe)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			Renderer[] componentsInChildren = ((Component)item).GetComponentsInChildren<Renderer>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				probe?.Add("Renderer=missing");
				return null;
			}
			Texture2D bestTexture = null;
			string bestSource = string.Empty;
			int bestScore = int.MinValue;
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				if (ShouldSkipRendererForIcon(val))
				{
					probe?.Add("Renderer(" + ((object)val).GetType().Name + ":" + ((Object)val).name + ")=skip");
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0)
				{
					probe?.Add("Renderer(" + ((object)val).GetType().Name + ":" + ((Object)val).name + ").sharedMaterials=empty");
					continue;
				}
				foreach (Material val2 in sharedMaterials)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					if (ShouldSkipMaterialForIcon(val2))
					{
						probe?.Add("Renderer(" + ((object)val).GetType().Name + ":" + ((Object)val).name + ").Material(" + ((Object)val2).name + ")=skip");
						continue;
					}
					string text = "Renderer(" + ((object)val).GetType().Name + ":" + ((Object)val).name + ").Material(" + ((Object)val2).name + ")";
					string name = ((Object)item).name;
					Texture mainTexture = val2.mainTexture;
					EvaluateTextureCandidate(name, (Texture2D?)(object)((mainTexture is Texture2D) ? mainTexture : null), text + ".mainTexture", ref bestTexture, ref bestSource, ref bestScore, probe);
					string[] array;
					try
					{
						array = val2.GetTexturePropertyNames();
					}
					catch
					{
						array = Array.Empty<string>();
					}
					foreach (string text2 in array)
					{
						if (!string.IsNullOrWhiteSpace(text2))
						{
							Texture2D texture = null;
							try
							{
								Texture texture2 = val2.GetTexture(text2);
								texture = (Texture2D)(object)((texture2 is Texture2D) ? texture2 : null);
							}
							catch
							{
							}
							EvaluateTextureCandidate(((Object)item).name, texture, text + "." + text2, ref bestTexture, ref bestSource, ref bestScore, probe);
						}
					}
				}
			}
			if ((Object)(object)bestTexture == (Object)null)
			{
				probe?.Add("MaterialTexture=no_candidate");
				return null;
			}
			if (bestScore < 80)
			{
				probe?.Add($"MaterialTexture.skip(score={bestScore})");
				return null;
			}
			probe?.Add($"MaterialTexture=choose(score={bestScore}):{bestSource}");
			return ConvertTextureToSprite(bestTexture, bestSource, probe);
		}

		private static bool ShouldSkipRendererForIcon(Renderer renderer)
		{
			if ((Object)(object)renderer == (Object)null)
			{
				return true;
			}
			string text = ((Object)renderer).name?.ToLowerInvariant() ?? string.Empty;
			if (!text.Contains("hand") && !text.Contains("arm") && !text.Contains("player") && !text.Contains("viewmodel") && !text.Contains("firstperson") && !text.Contains("fp_"))
			{
				return text.Contains("character");
			}
			return true;
		}

		private static bool ShouldSkipMaterialForIcon(Material material)
		{
			if ((Object)(object)material == (Object)null)
			{
				return true;
			}
			string text = ((Object)material).name?.ToLowerInvariant() ?? string.Empty;
			if (!text.Contains("m_player") && !text.Contains("player") && !text.Contains("hand") && !text.Contains("skin") && !text.Contains("hair") && !text.Contains("eye"))
			{
				return text.Contains("face");
			}
			return true;
		}

		private static void EvaluateTextureCandidate(string itemName, Texture2D? texture, string source, ref Texture2D? bestTexture, ref string bestSource, ref int bestScore, List<string>? probe)
		{
			if ((Object)(object)texture == (Object)null)
			{
				probe?.Add(source + "=null");
				return;
			}
			int num = ScoreTextureCandidate(itemName, texture, source);
			probe?.Add($"{source}=texture('{((Object)texture).name}') score={num}");
			if (num > bestScore)
			{
				bestScore = num;
				bestTexture = texture;
				bestSource = source;
			}
		}

		private static int ScoreTextureCandidate(string itemName, Texture2D texture, string source)
		{
			string text = source.ToLowerInvariant();
			string text2 = ((Object)texture).name ?? string.Empty;
			string text3 = text2.ToLowerInvariant();
			string source2 = (itemName ?? string.Empty).ToLowerInvariant();
			int num = 0;
			if (text.Contains("icon") || text.Contains("thumb"))
			{
				num += 120;
			}
			if (text3.Contains("icon") || text3.Contains("thumb"))
			{
				num += 100;
			}
			if (text.Contains("atlas"))
			{
				num += 25;
			}
			string value = new string(source2.Where(char.IsLetterOrDigit).ToArray());
			string text4 = new string(text3.Where(char.IsLetterOrDigit).ToArray());
			if (!string.IsNullOrEmpty(value) && text4.Contains(value))
			{
				num += 90;
			}
			if (text.Contains("_basemap") || text.Contains("_maintex") || text.Contains("_basetexture"))
			{
				num += 15;
			}
			if (((Texture)texture).width <= 1024 && ((Texture)texture).height <= 1024)
			{
				num += 20;
			}
			if (((Texture)texture).width <= 512 && ((Texture)texture).height <= 512)
			{
				num += 20;
			}
			if (((Texture)texture).width <= 256 && ((Texture)texture).height <= 256)
			{
				num += 10;
			}
			if (text.Contains("renderer(meshrenderer:hand)") || text.Contains("material(m_player)"))
			{
				num -= 300;
			}
			if (text3.StartsWith("a_texture") || text3.StartsWith("a_paint") || text3.StartsWith("a_noise"))
			{
				num -= 80;
			}
			if (text3.Contains("default") || text3.Contains("fallback") || text3.Contains("noise"))
			{
				num -= 60;
			}
			if (text3.Contains("soft noise") || text3 == "t_leaves" || text3.Contains("leaves") || text3.Contains("foliage"))
			{
				num -= 80;
			}
			return num;
		}

		private static bool ShouldEnumerateIconCollection(string source, object value)
		{
			if (value == null)
			{
				return false;
			}
			if (value is Array array)
			{
				Type c = array.GetType().GetElementType() ?? typeof(object);
				if (typeof(Sprite).IsAssignableFrom(c) || typeof(Texture).IsAssignableFrom(c))
				{
					return true;
				}
			}
			if (source.IndexOf("icon", StringComparison.OrdinalIgnoreCase) < 0 && source.IndexOf("sprite", StringComparison.OrdinalIgnoreCase) < 0 && source.IndexOf("thumb", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return source.IndexOf("texture", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static bool ShouldDeepProbeSource(string source, Type valueType)
		{
			if (valueType == null)
			{
				return false;
			}
			if (typeof(Texture).IsAssignableFrom(valueType) || typeof(Sprite).IsAssignableFrom(valueType))
			{
				return true;
			}
			if (source.IndexOf("icon", StringComparison.OrdinalIgnoreCase) < 0 && source.IndexOf("sprite", StringComparison.OrdinalIgnoreCase) < 0 && source.IndexOf("thumb", StringComparison.OrdinalIgnoreCase) < 0 && source.IndexOf("atlas", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return source.IndexOf("texture", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static bool IsIconProbeMember(string name, Type memberType)
		{
			if (memberType == null)
			{
				return false;
			}
			if (typeof(Sprite).IsAssignableFrom(memberType) || typeof(Texture).IsAssignableFrom(memberType) || memberType.IsArray)
			{
				return true;
			}
			string text = name?.ToLowerInvariant() ?? string.Empty;
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			if (!text.Contains("icon") && !text.Contains("sprite") && !text.Contains("thumbnail") && !text.Contains("atlas") && !text.Contains("texture"))
			{
				return text.Contains("tex");
			}
			return true;
		}

		private static string DescribeSprite(Sprite sprite)
		{
			//IL_004b: 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_0061: 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)
			if ((Object)(object)sprite == (Object)null)
			{
				return "sprite:null";
			}
			string text = (((Object)(object)sprite.texture != (Object)null) ? ((Object)sprite.texture).name : "null");
			object[] obj = new object[4]
			{
				((Object)sprite).name,
				text,
				null,
				null
			};
			Rect rect = sprite.rect;
			obj[2] = ((Rect)(ref rect)).width;
			rect = sprite.rect;
			obj[3] = ((Rect)(ref rect)).height;
			return string.Format("sprite='{0}', texture='{1}', rect={2}x{3}", obj);
		}

		private static string DescribeProbeValue(object? value)
		{
			if (value == null)
			{
				return "null";
			}
			Sprite val = (Sprite)((value is Sprite) ? value : null);
			if (val != null)
			{
				return DescribeSprite(val);
			}
			Texture val2 = (Texture)((value is Texture) ? value : null);
			if (val2 != null)
			{
				return "texture='" + ((Object)val2).name + "' (" + ((object)val2).GetType().Name + ")";
			}
			if (value is IEnumerable enumerable && !(value is string))
			{
				int num = 0;
				foreach (object item in enumerable)
				{
					num++;
					if (num >= 12)
					{
						break;
					}
				}
				return $"enumerable<{value.GetType().Name}> count~{num}";
			}
			Object val3 = (Object)((value is Object) ? value : null);
			if (val3 != null)
			{
				return "unity='" + val3.name + "' (" + ((object)val3).GetType().Name + ")";
			}
			string text = value.ToString() ?? value.GetType().Name;
			if (text.Length > 80)
			{
				text = text.Substring(0, 80) + "...";
			}
			return text;
		}

		private static string FormatProbe(List<string> probe)
		{
			if (probe == null || probe.Count == 0)
			{
				return "probe=empty";
			}
			if (probe.Count <= 20)
			{
				return string.Join(" | ", probe);
			}
			return string.Join(" | ", probe.Take(20)) + $" | ...(+{probe.Count - 20})";
		}
	}
	internal static class InputHandler
	{
		private static bool _inputSystemChecked;

		private static bool _inputSystemAvailable;

		private static PropertyInfo? _inputSystemKeyboardCurrentProp;

		private static PropertyInfo? _inputSystemKeyboardItemProp;

		private static PropertyInfo? _inputSystemKeyControlPressedProp;

		private static Type? _inputSystemKeyType;

		private static bool _legacyInputAvailable = true;

		public static bool IsTogglePressed()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			if (SharedState.ConfigToggleKey == null)
			{
				return false;
			}
			KeyCode value = SharedState.ConfigToggleKey.Value;
			if (TryGetInputSystemKeyDown(value, out var pressed))
			{
				return pressed;
			}
			if (TryGetLegacyInputKeyDown(value, out var pressed2))
			{
				return pressed2;
			}
			return false;
		}

		private static bool TryGetInputSystemKeyDown(KeyCode keyCode, out bool pressed)
		{
			pressed = false;
			if (!_inputSystemChecked)
			{
				_inputSystemAvailable = InitializeInputSystemReflection();
				_inputSystemChecked = true;
			}
			if (!_inputSystemAvailable)
			{
				return false;
			}
			try
			{
				object obj = _inputSystemKeyboardCurrentProp?.GetValue(null, null);
				if (obj == null)
				{
					return true;
				}
				object obj2 = Enum.Parse(_inputSystemKeyType, ((object)(KeyCode)(ref keyCode)).ToString());
				object obj3 = _inputSystemKeyboardItemProp?.GetValue(obj, new object[1] { obj2 });
				if (obj3 == null)
				{
					return true;
				}
				pressed = (bool)_inputSystemKeyControlPressedProp.GetValue(obj3, null);
				return true;
			}
			catch
			{
				_inputSystemAvailable = false;
				return false;
			}
		}

		private static bool InitializeInputSystemReflection()
		{
			try
			{
				Type type = Type.GetType("UnityEngine.InputSystem.Keyboard, Unity.InputSystem");
				_inputSystemKeyType = Type.GetType("UnityEngine.InputSystem.Key, Unity.InputSystem");
				Type type2 = Type.GetType("UnityEngine.InputSystem.Controls.KeyControl, Unity.InputSystem");
				if (type == null || _inputSystemKeyType == null || type2 == null)
				{
					return false;
				}
				_inputSystemKeyboardCurrentProp = type.GetProperty("current", BindingFlags.Static | BindingFlags.Public);
				_inputSystemKeyboardItemProp = type.GetProperty("Item", BindingFlags.Instance | BindingFlags.Public);
				_inputSystemKeyControlPressedProp = type2.GetProperty("wasPressedThisFrame", BindingFlags.Instance | BindingFlags.Public);
				return _inputSystemKeyboardCurrentProp != null && _inputSystemKeyboardItemProp != null && _inputSystemKeyControlPressedProp != null;
			}
			catch
			{
				return false;
			}
		}

		private static bool TryGetLegacyInputKeyDown(KeyCode keyCode, out bool pressed)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			pressed = false;
			if (!_legacyInputAvailable)
			{
				return false;
			}
			try
			{
				pressed = Input.GetKeyDown(keyCode);
				return true;
			}
			catch
			{
				_legacyInputAvailable = false;
				return false;
			}
		}
	}
	internal static class ItemLoader
	{
		[CompilerGenerated]
		private sealed class <BuildItemListGradually>d__8 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ItemDatabase db;

			public int dbId;

			private int <budget>5__2;

			private List<Item>.Enumerator <>7__wrap2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <BuildItemListGradually>d__8(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 2)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap2 = default(List<Item>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<budget>5__2 = 4;
						<>2__current = null;
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						<>7__wrap2 = ((DatabaseAsset<ItemDatabase, Item>)(object)db).Objects.GetEnumerator();
						<>1__state = -3;
						break;
					case 2:
						<>1__state = -3;
						break;
					}
					while (<>7__wrap2.MoveNext())
					{
						Item current = <>7__wrap2.Current;
						_preloadProcessedCount++;
						try
						{
							if ((Object)(object)current != (Object)null)
							{
								string resolvedItemDisplayName = GetResolvedItemDisplayName(current);
								if (!CategorySystem.ShouldHideItemFromBrowser(current))
								{
									ItemCategory category = CategorySystem.GetCategory(current, resolvedItemDisplayName);
									Sprite itemIcon = IconResolver.GetItemIcon(current, allowHeavyFallback: false);
									SharedState.ItemEntries.Add(new ItemEntry(current, resolvedItemDisplayName, category, itemIcon));
									_preloadAddedCount++;
								}
								else
								{
									Plugin.VerboseLog("Item hidden: prefab='" + ((Object)current).name + "', display='" + resolvedItemDisplayName + "'");
								}
							}
						}
						catch (Exception ex)
						{
							Plugin.Log.LogWarning((object)("[ItemBrowser] Preload item failed: " + ((current != null) ? ((Object)current).name : null) + " (" + ex.GetType().Name + " " + ex.Message + ")"));
						}
						<budget>5__2--;
						if (<budget>5__2 <= 0)
						{
							<budget>5__2 = 4;
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
					}
					<>m__Finally1();
					<>7__wrap2 = default(List<Item>.Enumerator);
					SharedState.ItemPreloadRunning = false;
					_preloadCoroutine = null;
					SharedState.ItemListInitialized = true;
					SharedState.LoadedDatabaseId = ((SharedState.PreloadingDatabaseId != 0) ? SharedState.PreloadingDatabaseId : dbId);
					SharedState.PreloadingDatabaseId = 0;
					if (SharedState.ConfigVerboseLogs != null && SharedState.ConfigVerboseLogs.Value)
					{
						IEnumerable<string> values = from entry in SharedState.ItemEntries
							group entry by entry.Category into @group
							orderby CategorySystem.GetCategoryOrder(@group.Key)
							select $"{CategorySystem.GetCategoryLabel(@group.Key)}={@group.Count()}";
						Plugin.Log.LogInfo((object)string.Format("[ItemBrowser] Item list built in background. Total={0}, Added={1}, Categories: {2}", SharedState.ItemEntries.Count, _preloadAddedCount, string.Join(", ", values)));
					}
					VirtualList.MarkListDirty("Item preload completed");
					IconResolver.TryStartBackgroundIconPrewarm("PostPreload");
					VirtualList.TryStartBackgroundButtonPoolWarmup("PostPreload", VirtualList.CalculateButtonPoolWarmupTarget(SharedState.ItemEntries.Count));
					if (SharedState.PageOpen)
					{
						VirtualList.RefreshListIfNeeded();
					}
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap2).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static Coroutine? _preloadCoroutine;

		private static int _preloadTotalCount;

		private static int _preloadProcessedCount;

		private static int _preloadAddedCount;

		private static float _nextPreloadCheckTime;

		internal static void EnsureItemList()
		{
			if (!SharedState.ItemListInitialized && !SharedState.ItemPreloadRunning)
			{
				TryStartBackgroundItemPreload("EnsureItemList");
			}
		}

		internal static void TickBackgroundItemPreload()
		{
			if (!SharedState.ItemListInitialized && !SharedState.ItemPreloadRunning && !(Time.unscaledTime < _nextPreloadCheckTime))
			{
				_nextPreloadCheckTime = Time.unscaledTime + 0.1f;
				TryStartBackgroundItemPreload("AutoWarmup");
			}
		}

		internal static bool TryStartBackgroundItemPreload(string reason)
		{
			if (SharedState.ItemListInitialized || SharedState.ItemPreloadRunning)
			{
				return false;
			}
			if ((Object)(object)SharedState.Instance == (Object)null)
			{
				return false;
			}
			ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance;
			if ((Object)(object)instance == (Object)null || ((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects == null || ((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects.Count == 0)
			{
				return false;
			}
			SharedState.ItemEntries.Clear();
			SharedState.ItemIconCache.Clear();
			SharedState.GeneratedTextureSpriteCache.Clear();
			IconResolver.ResetIconPrewarmState(stopCoroutine: true);
			VirtualList.ResetButtonPoolWarmupState(stopCoroutine: true);
			VirtualList.MarkListDirty("Item preload started (" + reason + ")");
			_preloadTotalCount = ((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects.Count;
			_preloadProcessedCount = 0;
			_preloadAddedCount = 0;
			SharedState.ItemPreloadRunning = true;
			SharedState.ItemNamesLanguageIndex = Localization.GetCurrentLanguageIndex();
			SharedState.ItemNamesLanguageMarker = Localization.BuildLanguageMarker();
			int dbId = (SharedState.PreloadingDatabaseId = ((Object)instance).GetInstanceID());
			SharedState.LoadedDatabaseId = 0;
			_preloadCoroutine = ((MonoBehaviour)SharedState.Instance).StartCoroutine(BuildItemListGradually(instance, dbId));
			Plugin.VerboseLog($"Item preload started ({reason}). Total={_preloadTotalCount}");
			return true;
		}

		[IteratorStateMachine(typeof(<BuildItemListGradually>d__8))]
		private static IEnumerator BuildItemListGradually(ItemDatabase db, int dbId)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <BuildItemListGradually>d__8(0)
			{
				db = db,
				dbId = dbId
			};
		}

		internal static string GetPreloadStatusText()
		{
			if (SharedState.ItemPreloadRunning)
			{
				if (_preloadTotalCount > 0)
				{
					return string.Format("{0} {1}/{2}", Localization.GetText("STATUS_LOADING"), _preloadProcessedCount, _preloadTotalCount);
				}
				return Localization.GetText("STATUS_LOADING");
			}
			return Localization.GetText("STATUS_NOT_READY");
		}

		internal static string GetResolvedItemDisplayName(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return string.Empty;
			}
			string localizedItemName = Localization.GetLocalizedItemName(item);
			string displayName = (string.IsNullOrWhiteSpace(localizedItemName) ? (((Object)item).name ?? string.Empty) : localizedItemName);
			return GetDisplayNameOverride(item, displayName);
		}

		private static string GetDisplayNameOverride(Item item, string displayName)
		{
			if ((Object)(object)item == (Object)null)
			{
				return displayName;
			}
			string text = ((Object)item).name ?? string.Empty;
			if (text.Equals("EggTurkey", StringComparison.OrdinalIgnoreCase))
			{
				string text2 = Localization.ResolveLocalizedText("NAME_COOKED BIRD");
				if (!string.IsNullOrWhiteSpace(text2))
				{
					return text2;
				}
				return displayName;
			}
			return displayName;
		}

		internal static void RefreshItemDisplayNamesForCurrentLanguage(bool force = false, string? currentLanguageMarker = null)
		{
			if (!SharedState.ItemListInitialized || SharedState.ItemEntries.Count == 0)
			{
				return;
			}
			int currentLanguageIndex = Localization.GetCurrentLanguageIndex();
			if (currentLanguageMarker == null)
			{
				currentLanguageMarker = Localization.BuildLanguageMarker();
			}
			bool flag = !string.Equals(currentLanguageMarker, SharedState.ItemNamesLanguageMarker, StringComparison.Ordinal);
			if (!force && !flag && currentLanguageIndex == SharedState.ItemNamesLanguageIndex)
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < SharedState.ItemEntries.Count; i++)
			{
				ItemEntry itemEntry = SharedState.ItemEntries[i];
				string resolvedItemDisplayName = GetResolvedItemDisplayName(itemEntry.Prefab);
				if (!string.Equals(itemEntry.DisplayName, resolvedItemDisplayName, StringComparison.Ordinal))
				{
					itemEntry.UpdateDisplayName(resolvedItemDisplayName);
					num++;
				}
			}
			SharedState.ItemNamesLanguageIndex = currentLanguageIndex;
			SharedState.ItemNamesLanguageMarker = currentLanguageMarker;
			Plugin.VerboseLog($"Language refresh complete. index={currentLanguageIndex}, renamed={num}, total={SharedState.ItemEntries.Count}, markerChanged={flag}");
		}

		internal static void ResetState()
		{
			StopTrackedCoroutine(ref _preloadCoroutine);
			_preloadTotalCount = 0;
			_preloadProcessedCount = 0;
			_preloadAddedCount = 0;
			_nextPreloadCheckTime = 0f;
		}

		private static void StopTrackedCoroutine(ref Coroutine? coroutine)
		{
			if (coroutine != null)
			{
				if ((Object)(object)SharedState.Instance != (Object)null)
				{
					((MonoBehaviour)SharedState.Instance).StopCoroutine(coroutine);
				}
				coroutine = null;
			}
		}
	}
	[ConsoleClassCustomizer("ItemBrowser")]
	internal static class ItemSpawner
	{
		[ConsoleCommand(false)]
		public static void Spawn(Item item)
		{
			string statusMessage;
			if ((Object)(object)item == (Object)null)
			{
				ReportConsoleWarning("[ItemBrowser] Spawn command failed: resolved item was null.");
			}
			else if (!TrySpawnItem(item, out statusMessage))
			{
				ReportConsoleWarning(statusMessage);
			}
			else
			{
				ReportConsoleInfo(statusMessage);
			}
		}

		public static void SpawnItem(Item prefab)
		{
			TrySpawnItem(prefab, out string _);
		}

		private static bool IsCharacterDeadOrGhost(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return true;
			}
			if ((Object)(object)character.data == (Object)null)
			{
				return true;
			}
			if (!character.data.dead && !character.IsGhost)
			{
				return character.data.fullyPassedOut;
			}
			return true;
		}

		private static Character? ResolveSpawnTarget(Character localPlayer, out string? warningMessage)
		{
			warningMessage = null;
			if (!SharedState.ConfigGhostSendToObserved.Value || !IsCharacterDeadOrGhost(localPlayer))
			{
				return localPlayer;
			}
			Character observedCharacter = Character.observedCharacter;
			if ((Object)(object)observedCharacter == (Object)null)
			{
				warningMessage = "[ItemBrowser] You are dead/ghost but not spectating anyone. Cannot send item.";
				return null;
			}
			if (IsCharacterDeadOrGhost(observedCharacter))
			{
				string text = ((Object)observedCharacter).name ?? "unknown";
				warningMessage = "[ItemBrowser] Spectated player '" + text + "' is also dead or incapacitated. Cannot send item.";
				return null;
			}
			return observedCharacter;
		}

		private static bool TrySpawnItem(Item prefab, out string statusMessage)
		{
			statusMessage = string.Empty;
			if ((Object)(object)prefab == (Object)null)
			{
				statusMessage = "[ItemBrowser] Item prefab is null.";
				return false;
			}
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null)
			{
				statusMessage = "[ItemBrowser] No local character available. Enter a match to spawn items.";
				Plugin.Log.LogWarning((object)statusMessage);
				return false;
			}
			if (!SharedState.ConfigAllowOnline.Value && !PhotonNetwork.OfflineMode && (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom))
			{
				statusMessage = "[ItemBrowser] Online spawn disabled or not in room.";
				Plugin.Log.LogWarning((object)statusMessage);
				return false;
			}
			string warningMessage;
			Character val = ResolveSpawnTarget(localCharacter, out warningMessage);
			if ((Object)(object)val == (Object)null)
			{
				statusMessage = warningMessage ?? "[ItemBrowser] No valid spawn target found.";
				Plugin.Log.LogWarning((object)statusMessage);
				return false;
			}
			bool flag = (Object)(object)val != (Object)(object)localCharacter;
			string text = (flag ? ("observed teammate '" + (((Object)val).name ?? "unknown") + "'") : "local player");
			if (flag)
			{
				Plugin.VerboseLog("Ghost redirect -> " + text);
			}
			PhotonView photonView = ((MonoBehaviourPun)val).photonView;
			string text2 = ((photonView != null) ? photonView.ViewID.ToString() : null) ?? "null";
			Plugin.VerboseLog($"Spawn: '{((Object)prefab).name}', target={text}, viewId={text2}, online={PhotonNetwork.IsConnected}, inRoom={PhotonNetwork.InRoom}");
			try
			{
				if ((Object)(object)GameUtils.instance != (Object)null)
				{
					GameUtils.instance.InstantiateAndGrab(prefab, val, 0);
					Plugin.VerboseLog("Spawn completed: " + ((Object)prefab).name);
					statusMessage = (flag ? ("[ItemBrowser] Spawned " + FormatItemCommandLabel(prefab) + " -> sent to " + text + ".") : ("[ItemBrowser] Spawned " + FormatItemCommandLabel(prefab) + "."));
					return true;
				}
				statusMessage = "[ItemBrowser] GameUtils.instance is null, cannot spawn " + ((Object)prefab).name + ".";
				Plugin.Log.LogError((object)statusMessage);
				return false;
			}
			catch (Exception ex)
			{
				statusMessage = "[ItemBrowser] Spawn failed for " + ((Object)prefab).name + ": " + ex.Message;
				Plugin.Log.LogError((object)statusMessage);
				return false;
			}
		}

		private static string FormatItemCommandLabel(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return "<null>";
			}
			string text = Localization.NormalizeItemNameForMap(((Object)item).name ?? string.Empty);
			string text2 = ItemLoader.GetResolvedItemDisplayName(item).Trim();
			if (string.IsNullOrWhiteSpace(text2) || string.Equals(text2, text, StringComparison.OrdinalIgnoreCase))
			{
				return "'" + text + "'";
			}
			return "'" + text2 + "' (" + text + ")";
		}

		private static void ReportConsoleInfo(string message)
		{
			if (!string.IsNullOrWhiteSpace(message))
			{
				Plugin.Log.LogInfo((object)message);
				Debug.Log((object)message);
			}
		}

		private static void ReportConsoleWarning(string message)
		{
			if (!string.IsNullOrWhiteSpace(message))
			{
				Plugin.Log.LogWarning((object)message);
				Debug.LogWarning((object)message);
			}
		}

		public static void RefreshConsoleCommands()
		{
			try
			{
				ConsoleHandler.Initialize(ConsoleHandler.ScanForConsoleCommands(), ConsoleHandler.ScanForTypeParsers());
				Plugin.VerboseLog("Console commands refreshed.");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[ItemBrowser] Failed to refresh console commands: " + ex.GetType().Name + " " + ex.Message));
			}
		}
	}
	internal static class Localization
	{
		private static readonly Dictionary<string, List<string>> _localizedTextTable = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, string> _itemNameKeyMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static bool _itemNameKeyMapInitialized;

		private static int _lastRenderedLanguageIndex = -1;

		internal static int LastRenderedLanguageIndex
		{
			get
			{
				return _lastRenderedLanguageIndex;
			}
			set
			{
				_lastRenderedLanguageIndex = value;
			}
		}

		internal static string GetLocalizedItemName(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return string.Empty;
			}
			EnsureItemNameKeyMap();
			string text = ((Object)item).name ?? string.Empty;
			if (ContainsNonAscii(text))
			{
				return text.Trim();
			}
			string text2 = NormalizeItemNameForMap(text);
			if (!string.IsNullOrEmpty(text2) && _itemNameKeyMap.TryGetValue(text2, out string value))
			{
				return ResolveLocalizedText(value);
			}
			return string.Empty;
		}

		private static void EnsureItemNameKeyMap()
		{
			if (!_itemNameKeyMapInitialized)
			{
				LoadItemNameKeyMap();
				_itemNameKeyMapInitialized = true;
			}
		}

		private static void LoadItemNameKeyMap()
		{
			_itemNameKeyMap.Clear();
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ItemNameKeyMap.json");
				if (stream == null)
				{
					Plugin.Log.LogWarning((object)"[ItemBrowser] Embedded ItemNameKeyMap.json not found.");
					return;
				}
				using StreamReader streamReader = new StreamReader(stream);
				string text = streamReader.ReadToEnd();
				Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(text);
				if (dictionary == null)
				{
					return;
				}
				foreach (KeyValuePair<string, string> item in dictionary)
				{
					if (!string.IsNullOrWhiteSpace(item.Key) && !string.IsNullOrWhiteSpace(item.Value))
					{
						_itemNameKeyMap[item.Key] = item.Value;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[ItemBrowser] Failed to load embedded ItemNameKeyMap.json: " + ex.GetType().Name + " " + ex.Message));
			}
		}

		internal static string NormalizeItemNameForMap(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return string.Empty;
			}
			string text = StripLocPrefix(name.Trim());
			return text.Replace("(Clone)", "").Trim();
		}

		private static bool ContainsNonAscii(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			for (int i = 0; i < text.Length; i++)
			{
				if (text[i] > '\u007f')
				{
					return true;
				}
			}
			return false;
		}

		private static string StripLocPrefix(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return string.Empty;
			}
			if (key.StartsWith("LOC:", StringComparison.OrdinalIgnoreCase))
			{
				return key.Substring("LOC:".Length).Trim();
			}
			return key;
		}

		internal static string ResolveLocalizedText(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return string.Empty;
			}
			try
			{
				string text = StripLocPrefix(key.Trim());
				if (string.IsNullOrEmpty(text))
				{
					return string.Empty;
				}
				string text2 = LocalizedText.GetText(text, true);
				if (string.IsNullOrEmpty(text2))
				{
					return string.Empty;
				}
				string text3 = text2.Trim();
				if (text3.StartsWith("LOC:", StringComparison.OrdinalIgnoreCase))
				{
					return string.Empty;
				}
				if (string.Equals(text3, text, StringComparison.OrdinalIgnoreCase))
				{
					return string.Empty;
				}
				return text3;
			}
			catch
			{
				return string.Empty;
			}
		}

		internal static string GetText(string key, params string[] args)
		{
			string text = (GetLocalizationPrefix() + "_" + key).ToUpperInvariant();
			string text2 = LocalizedText.GetText(text, true);
			if (IsMissingLocalization(text2, text))
			{
				EnsureLocalizedTextInjected();
				text2 = LocalizedText.GetText(text, true);
			}
			if (IsMissingLocalization(text2, text))
			{
				text2 = GetCachedLocalizedText(key);
			}
			if (string.IsNullOrEmpty(text2))
			{
				text2 = key;
			}
			return string.Format(text2, args);
		}

		internal static void LoadLocalizedText()
		{
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Localized_Text.json");
				if (stream == null)
				{
					Plugin.Log.LogWarning((object)"[ItemBrowser] Embedded Localized_Text.json not found.");
					return;
				}
				using StreamReader streamReader = new StreamReader(stream);
				string text = streamReader.ReadToEnd();
				Dictionary<string, List<string>> dictionary = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(text);
				if (dictionary == null)
				{
					Plugin.Log.LogWarning((object)"[ItemBrowser] Localized_Text.json deserialized to null.");
					return;
				}
				_localizedTextTable.Clear();
				foreach (KeyValuePair<string, List<string>> item in dictionary)
				{
					if (string.IsNullOrWhiteSpace(item.Key))
					{
						continue;
					}
					List<string> value = item.Value;
					if (value == null || value.Count == 0)
					{
						_localizedTextTable[item.Key] = new List<string> { item.Key };
						continue;
					}
					string firstValue = value.FirstOrDefault((string x) => !string.IsNullOrWhiteSpace(x)) ?? item.Key;
					List<string> list = value.Select((string x) => (!string.IsNullOrWhiteSpace(x)) ? x : firstValue).ToList();
					if (list.Count == 0)
					{
						list.Add(firstValue);
					}
					_localizedTextTable[item.Key] = list;
				}
				EnsureLocalizedTextInjected();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[ItemBrowser] Failed to load Localized_Text.json: " + ex.GetType().Name + " " + ex.Message));
			}
		}

		private static string GetLocalizationPrefix()
		{
			return "Mod_" + Plugin.Name;
		}

		internal static void EnsureLocalizedTextInjected()
		{
			if (_localizedTextTable.Count == 0)
			{
				return;
			}
			if (LocalizedText.MAIN_TABLE == null)
			{
				Plugin.Log.LogWarning((object)"[ItemBrowser] LocalizedText.MAIN_TABLE is null. Skip localization injection.");
				return;
			}
			string localizationPrefix = GetLocalizationPrefix();
			foreach (KeyValuePair<string, List<string>> item in _localizedTextTable)
			{
				if (!string.IsNullOrWhiteSpace(item.Key) && item.Value != null && item.Value.Count != 0)
				{
					string key = (localizationPrefix + "_" + item.Key).ToUpperInvariant();
					LocalizedText.MAIN_TABLE[key] = item.Value;
				}
			}
		}

		private static bool IsMissingLocalization(string? text, string key)
		{
			if (string.IsNullOrWhiteSpace(text))
			{
				return true;
			}
			string text2 = text.Trim();
			if (text2.StartsWith("LOC:", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (string.Equals(text2, key, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return false;
		}

		private static string GetCachedLocalizedText(string key)
		{
			if (!_localizedTextTable.TryGetValue(key, out List<string> value) || value == null || value.Count == 0)
			{
				return string.Empty;
			}
			int num = GetCurrentLanguageIndex();
			if (num < 0 || num >= value.Count)
			{
				num = 0;
			}
			string text = value[num];
			if (string.IsNullOrWhiteSpace(text))
			{
				text = value[0];
			}
			return text?.Trim() ?? string.Empty;
		}

		internal static int GetCurrentLanguageIndex()
		{
			try
			{
				Type typeFromHandle = typeof(LocalizedText);
				string[] array = new string[6] { "CurrentLanguageIndex", "CurrentLanguage", "LanguageIndex", "Language", "currentLanguageIndex", "currentLanguage" };
				string[] array2 = array;
				foreach (string name in array2)
				{
					PropertyInfo property = typeFromHandle.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if (!(property == null))
					{
						object value = property.GetValue(null);
						if (TryConvertLanguageIndex(value, out var index))
						{
							return NormalizeLanguageIndex(index);
						}
					}
				}
				string[] array3 = array;
				foreach (string name2 in array3)
				{
					FieldInfo field = typeFromHandle.GetField(name2, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					if (!(field == null))
					{
						object value2 = field.GetValue(null);
						if (TryConvertLanguageIndex(value2, out var index2))
						{
							return NormalizeLanguageIndex(index2);
						}
					}
				}
			}
			catch
			{
			}
			return 0;
		}

		private static int NormalizeLanguageIndex(int index)
		{
			if (index >= 0)
			{
				return index;
			}
			return 0;
		}

		private static bool TryConvertLanguageIndex(object? value, out int index)
		{
			index = 0;
			if (value == null)
			{
				return false;
			}
			if (value is int num)
			{
				index = num;
				return true;
			}
			if (value is Enum value2)
			{
				index = Convert.ToInt32(value2);
				return true;
			}
			if (value is byte b)
			{
				index = b;
				return true;
			}
			if (value is short num2)
			{
				index = num2;
				return true;
			}
			if (value is long num3)
			{
				index = (int)num3;
				return true;
			}
			return false;
		}

		internal static string GetTextOrFallback(string key, string fallback)
		{
			string text = GetText(key);
			if (string.IsNullOrWhiteSpace(text) || string.Equals(text, key, StringComparison.OrdinalIgnoreCase))
			{
				return fallback;
			}
			return text;
		}

		internal static string BuildLanguageMarker()
		{
			return GetText("TITLE") + "|" + GetText("SEARCH_PLACEHOLDER");
		}
	}
	internal enum MajorCategory
	{
		All,
		Food,
		Weapon
	}
	internal enum ItemCategory
	{
		NaturalFood,
		MysticalFood,
		PackagedFood,
		Mushroom,
		Consumable,
		Deployable,
		MiscEquipment,
		MysticalItem
	}
	internal sealed class ItemEntry
	{
		public Item Prefab { get; }

		public string PrefabName { get; }

		public string DisplayName { get; private set; } = string.Empty;


		public ItemCategory Category { get; }

		public Sprite? Icon { get; private set; }

		public string SearchText { get; private set; } = string.Empty;


		public ItemEntry(Item prefab, string displayName, ItemCategory category, Sprite? icon)
		{
			Prefab = prefab;
			PrefabName = ((Object)prefab).name ?? string.Empty;
			Category = category;
			Icon = icon;
			UpdateDisplayName(displayName);
		}

		public void UpdateIcon(Sprite? icon)
		{
			Icon = icon;
		}

		public void UpdateDisplayName(string displayName)
		{
			string text2 = (DisplayName = (string.IsNullOrWhiteSpace(displayName) ? PrefabName : displayName.Trim()));
			SearchText = (text2 + " " + PrefabName).ToLowerInvariant();
		}
	}
	internal sealed class PooledItemButton
	{
		public PeakMenuButton Button { get; }

		public RectTransform ButtonRect { get; }

		public Image IconImage { get; }

		public ItemButtonBinder Binder { get; }

		public int PoolIndex { get; }

		public int BoundDataIndex { get; set; }

		public PooledItemButton(PeakMenuButton button, RectTransform buttonRect, Image iconImage, ItemButtonBinder binder, int poolIndex)
		{
			Button = button;
			ButtonRect = buttonRect;
			IconImage = iconImage;
			Binder = binder;
			PoolIndex = poolIndex;
			BoundDataIndex = -1;
		}
	}
	internal sealed class ItemButtonBinder : MonoBehaviour
	{
		public Item? Prefab;

		public void HandleClick()
		{
			if ((Object)(object)Prefab != (Object)null)
			{
				ItemSpawner.SpawnItem(Prefab);
			}
		}
	}
	internal sealed class CategoryTab
	{
		public ItemCategory? Category { get; }

		public GameObject Root { get; }

		public Button Button { get; }

		public Image Background { get; }

		public Image Selected { get; }

		public PeakText Label { get; }

		public CategoryTab(ItemCategory? category, GameObject root, Button button, Image background, Image selected, PeakText label)
		{
			Category = category;
			Root = root;
			Button = button;
			Background = background;
			Selected = selected;
			Label = label;
		}
	}
	internal sealed class MajorCategoryTab
	{
		public MajorCategory Category { get; }

		public GameObject Root { get; }

		public Button Button { get; }

		public Image Background { get; }

		public Image Selected { get; }

		public PeakText Label { get; }

		public MajorCategoryTab(MajorCategory category, GameObject root, Button button, Image background, Image selected, PeakText label)
		{
			Category = category;
			Root = root;
			Button = button;
			Background = background;
			Selected = selected;
			Label = label;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.github.cherrycove.ItemBrowser", "ItemBrowser", "0.2.4")]
	public class Plugin : BaseUnityPlugin
	{
		private static float _nextUIWarmupCheckTime;

		private static bool _firstOpenPrimed;

		private static bool _hiddenMenuWindowPrimed;

		private static bool _postSpawnPrimeLocked;

		private static float _nextHiddenPrimeCheckTime;

		private static float _nextPostSpawnPrimeCheckTime;

		public const string Id = "com.github.cherrycove.ItemBrowser";

		internal static ManualLogSource Log { get; private set; }

		public static string Name => "ItemBrowser";

		public static string Version => "0.2.4";

		private void Awake()
		{
			SharedState.Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			SharedState.ConfigToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("ItemBrowser", "Toggle Key", (KeyCode)286, "Press to open/close the item browser.");
			SharedState.ConfigAllowOnline = ((BaseUnityPlugin)this).Config.Bind<bool>("ItemBrowser", "Allow Online Spawn", true, "Allow spawning items while online.");
			SharedState.ConfigVerboseLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("ItemBrowser", "Verbose Logs", false, "Enable detailed category/UI/spawn logs.");
			SharedState.ConfigGhostSendToObserved = ((BaseUnityPlugin)this).Config.Bind<bool>("ItemBrowser", "Ghost Send To Observed", true, "When dead or in ghost/spectate mode, send spawned items to the currently observed teammate instead of the local (dead) character.");
			Localization.LoadLocalizedText();
			ItemSpawner.RefreshConsoleCommands();
		}

		private void OnDestroy()
		{
			if ((Object)(object)SharedState.Instance == (Object)(object)this)
			{
				SharedState.Instance = null;
			}
			ItemLoader.ResetState();
			IconResolver.ResetIconPrewarmState(stopCoroutine: true);
			VirtualList.ResetState();
		}

		private void Update()
		{
			ValidateRuntimeState();
			VirtualList.TickVirtualizedScrollApply();
			TickBackgroundUIWarmup();
			ItemLoader.TickBackgroundItemPreload();
			IconResolver.TickBackgroundIconPrewarm();
			VirtualList.TickBackgroundButtonPoolWarmup();
			TickHiddenFirstOpenPrime();
			TickPostSpawnPrimeLock();
			if (InputHandler.IsTogglePressed())
			{
				ToggleUI();
			}
		}

		private static void ValidateRuntimeState()
		{
			if (SharedState.UiBuilt && (Object)(object)SharedState.Page == (Object)null)
			{
				UIBuilder.ResetState("Cached UI page was destroyed.");
			}
			ItemDatabase instance = SingletonAsset<ItemDatabase>.Instance;
			if (!((Object)(object)instance == (Object)null) && ((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects != null && ((DatabaseAsset<ItemDatabase, Item>)(object)instance).Objects.Count != 0)
			{
				int instanceID = ((Object)instance).GetInstanceID();
				if (SharedState.ItemPreloadRunning && SharedState.PreloadingDatabaseId != 0 && SharedState.PreloadingDatabaseId != instanceID)
				{
					InvalidateItemListState($"ItemDatabase changed while preloading ({SharedState.PreloadingDatabaseId}->{instanceID}).");
				}
				else if (!SharedState.ItemPreloadRunning && SharedState.ItemListInitialized && SharedState.LoadedDatabaseId != 0 && SharedState.LoadedDatabaseId != instanceID)
				{
					InvalidateItemListState($"ItemDatabase changed ({SharedState.LoadedDatabaseId}->{instanceID}). Re-preloading.");
				}
			}
		}

		private static void InvalidateItemListState(string reason)
		{
			ItemLoader.ResetState();
			IconResolver.ResetIconPrewarmState(stopCoroutine: true);
			SharedState.ItemListInitialized = false;
			SharedState.PreloadingDatabaseId = 0;
			SharedState.LoadedDatabaseId = 0;
			SharedState.ItemNamesLanguageIndex = -1;
			SharedState.ItemNamesLanguageMarker = string.Empty;
			SharedState.ListNeedsRefresh = true;
			SharedState.ListRenderRunning = false;
			SharedState.ListRenderGeneration++;
			_firstOpenPrimed = false;
			_hiddenMenuWindowPrimed = false;
			_postSpawnPrimeLocked = false;
			_nextHiddenPrimeCheckTime = 0f;
			_nextPostSpawnPrimeCheckTime = 0f;
			SharedState.ItemEntries.Clear();
			SharedState.ItemIconCache.Clear();
			SharedState.GeneratedTextureSpriteCache.Clear();
			SharedState.ItemButtonPool.Clear();
			SharedState.ActiveRenderEntries.Clear();
			VirtualList.ResetState();
			VirtualList.ResetButtonPoolWarmupState(stopCoroutine: true);
			VerboseLog(reason);
			VirtualList.MarkListDirty(reason);
			if (SharedState.PageOpen)
			{
				VirtualList.RefreshListIfNeeded(force: true);
			}
		}

		private static void TickBackgroundUIWarmup()
		{
			if (!SharedState.UiBuilt && !(Time.unscaledTime < _nextUIWarmupCheckTime))
			{
				_nextUIWarmupCheckTime = Time.unscaledTime + 0.1f;
				if (UIBuilder.IsUIReady(out string _))
				{
					UIBuilder.BuildUI();
					SharedState.UiBuilt = true;
					VerboseLog("UI warmup build completed.");
				}
			}
		}

		private static void ToggleUI()
		{
			if (EnsureUIBuilt())
			{
				if (SharedState.PageOpen)
				{
					UIBuilder.ClosePage();
				}
				else
				{
					UIBuilder.OpenPage();
				}
			}
		}

		private static bool EnsureUIBuilt()
		{
			if (SharedState.UiBuilt)
			{
				if ((Object)(object)SharedState.Page != (Object)null)
				{
					return true;
				}
				UIBuilder.ResetState("Cached UI page was destroyed.");
			}
			if (!UIBuilder.IsUIReady(out string reason))
			{
				Log.LogWarning((object)("[ItemBrowser] UI not ready yet (" + reason + "). Try again after fully entering a match."));
				return false;
			}
			UIBuilder.BuildUI();
			SharedState.UiBuilt = true;
			VerboseLog("UI build completed.");
			return true;
		}

		private static void TickHiddenFirstOpenPrime()
		{
			if (!_firstOpenPrimed && !SharedState.PageOpen && SharedState.UiBuilt && !((Object)(object)SharedState.ScrollContent == (Object)null) && SharedState.ItemListInitialized && !SharedState.ItemPreloadRunning && !((Object)(object)Character.localCharacter != (Object)null) && !(Time.unscaledTime < _nextHiddenPrimeCheckTime))
			{
				_nextHiddenPrimeCheckTime = Time.unscaledTime + 0.25f;
				TabsManager.RefreshLanguageDependentContent();
				VirtualList.RefreshListIfNeeded();
				if (!_hiddenMenuWindowPrimed && (Object)(object)Character.localCharacter == (Object)null)
				{
					PrimeMenuWindowOpenClose();
				}
				if (!SharedState.ListNeedsRefresh && !SharedState.ListRenderRunning)
				{
					_firstOpenPrimed = true;
					VerboseLog("Hidden first-open cache primed.");
				}
			}
		}

		private static void PrimeMenuWindowOpenClose()
		{
			if (_hiddenMenuWindowPrimed || (Object)(object)SharedState.Page == (Object)null || SharedState.PageOpen)
			{
				return;
			}
			try
			{
				UIBuilder.OpenPage();
				Canvas.ForceUpdateCanvases();
				RectTransform listContent = VirtualList.GetListContent();
				if ((Object)(object)listContent != (Object)null)
				{
					LayoutRebuilder.ForceRebuildLayoutImmediate(listContent);
				}
				UIBuilder.ClosePage();
				Canvas.ForceUpdateCanvases();
				_hiddenMenuWindowPrimed = true;
				VerboseLog("Menu window warmup completed before first manual F5.");
			}
			catch (Exception ex)
			{
				VerboseLog("Menu window warmup failed: " + ex.GetType().Name + " " + ex.Message);
			}
		}

		private static void TickPostSpawnPrimeLock()
		{
			if (_postSpawnPrimeLocked || SharedState.PageOpen || !SharedState.UiBuilt || (Object)(object)SharedState.ScrollContent == (Object)null || (Object)(object)Character.localCharacter == (Object)null || Time.unscaledTime < _nextPostSpawnPrimeCheckTime)
			{
				return;
			}
			_nextPostSpawnPrimeCheckTime = Time.unscaledTime + 0.1f;
			if (!_hiddenMenuWindowPrimed)
			{
				PrimeMenuWindowOpenClose();
			}
			if (SharedState.ItemListInitialized && !SharedState.ItemPreloadRunning)
			{
				TabsManager.RefreshLanguageDependentContent();
				VirtualList.RefreshListIfNeeded();
				if (!SharedState.ListNeedsRefresh && !SharedState.ListRenderRunning && _hiddenMenuWindowPrimed)
				{
					_postSpawnPrimeLocked = true;
					VerboseLog("Post-spawn prime lock completed.");
				}
			}
		}

		internal static void VerboseLog(string message)
		{
			if (SharedState.ConfigVerboseLogs.Value)
			{
				Log.LogInfo((object)("[ItemBrowser] " + message));
			}
		}
	}
	internal static class SharedState
	{
		public static ConfigEntry<KeyCode>? ConfigToggleKey;

		public static ConfigEntry<bool>? ConfigAllowOnline;

		public static ConfigEntry<bool>? ConfigVerboseLogs;

		public static ConfigEntry<bool>? ConfigGhostSendToObserved;

		public static readonly Color TabInactiveBg = new Color(0.22f, 0.17f, 0.12f, 0.95f);

		public static readonly Color TabActiveBg = new Color(0.95f, 0.92f, 0.86f, 1f);

		public static readonly Color TabInactiveText = new Color(0.92f, 0.88f, 0.8f, 1f);

		public static readonly Color TabActiveText = new Color(0.2f, 0.16f, 0.12f, 1f);

		public static readonly Color TabHighlightedBg = new Color(0.26f, 0.2f, 0.14f, 1f);

		public static readonly Color TabPressedBg = new Color(0.16f, 0.12f, 0.09f, 1f);

		public static PeakCustomPage? Page;

		public static PeakText? HeaderTitleText;

		public static PeakMenuButton? CloseMenuButton;

		public static PeakTextInput? SearchInput;

		public static PeakScrollableContent? ScrollContent;

		public static PeakHorizontalTabs? MajorTabs;

		public static PeakHorizontalTabs? SubCategoryTabs;

		public static GameObject? SubCategoryTabsRoot;

		public static RectTransform? TopControlsRect;

		public static RectTransform? ListContainerRect;

		public static ScrollRect? ListScrollRect;

		public static GridLayoutGroup? ItemGridLayout;

		public static Plugin? Instance;

		public static bool UiBuilt;

		public static bool PageOpen;

		public static bool ListNeedsRefresh = true;

		public static bool ListRenderRunning;

		public static int ListRenderGeneration;

		public static readonly List<ItemEntry> ItemEntries = new List<ItemEntry>();

		public static bool ItemListInitialized;

		public static bool ItemPreloadRunning;

		public static int PreloadingDatabaseId;

		public static int LoadedDatabaseId;

		public static int ItemNamesLanguageIndex = -1;

		public static string ItemNamesLanguageMarker = string.Empty;

		public static readonly Dictionary<string, Sprite?> ItemIconCache = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);

		public static readonly Dictionary<int, Sprite> GeneratedTextureSpriteCache = new Dictionary<int, Sprite>();

		public static readonly List<PooledItemButton> ItemButtonPool = new List<PooledItemButton>();

		public static readonly List<ItemEntry> ActiveRenderEntries = new List<ItemEntry>();

		public static string CurrentSearch = string.Empty;

		public static MajorCategory CurrentMajorFilter = MajorCategory.All;

		public static ItemCategory? CurrentSubCategoryFilter;

		public static readonly List<MajorCategoryTab> MajorTabEntries = new List<MajorCategoryTab>();

		public static readonly List<CategoryTab> SubCategoryTabEntries = new List<CategoryTab>();

		public static string LastLanguageMarker = string.Empty;
	}
	internal static class TabsManager
	{
		internal static void BuildMajorTabs(PeakHorizontalTabs tabs)
		{
			if (!((Object)(object)tabs == (Object)null))
			{
				SharedState.MajorTabEntries.Clear();
				AddMajorTab(tabs, CategorySystem.GetMajorCategoryLabel(MajorCategory.All), MajorCategory.All, 226.67f);
				AddMajorTab(tabs, CategorySystem.GetMajorCategoryLabel(MajorCategory.Food), MajorCategory.Food, 226.67f);
				AddMajorTab(tabs, CategorySystem.GetMajorCategoryLabel(MajorCategory.Weapon), MajorCategory.Weapon, 226.67f);
				UpdateMajorTabs();
			}
		}

		private static void AddMajorTab(PeakHorizontalTabs tabs, string label, MajorCategory category, float width)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			GameObject val = tabs.AddTab(label);
			if (TrySetupTabVisual(val, width, 44f, out Button button, out Image background, out Image selected, out PeakText labelText))
			{
				MajorCategoryTab majorCategoryTab = new MajorCategoryTab(category, val, button, background, selected, labelText);
				SharedState.MajorTabEntries.Add(majorCategoryTab);
				((UnityEvent)button.onClick).AddListener((UnityAction)delegate
				{
					SharedState.CurrentMajorFilter = category;
					SharedState.CurrentSubCategoryFilter = null;
					UpdateMajorTabs();
					RebuildSubCategoryTabs();
					UpdateSubCategoryVisibility();
					VirtualList.MarkListDirty("Major category changed");
					VirtualList.RefreshListIfNeeded(force: true);
				});
				ApplyMajorTabStyle(majorCategoryTab, category == SharedState.CurrentMajorFilter);
			}
		}

		internal static void UpdateMajorTabs()
		{
			for (int i = 0; i < SharedState.MajorTabEntries.Count; i++)
			{
				MajorCategoryTab majorCategoryTab = SharedState.MajorTabEntries[i];
				bool selected = majorCategoryTab.Category == SharedState.CurrentMajorFilter;
				ApplyMajorTabStyle(majorCategoryTab, selected);
			}
		}

		internal static void RebuildSubCategoryTabs()
		{
			if ((Object)(object)SharedState.SubCategoryTabs == (Object)null)
			{
				return;
			}
			Transform val = ((Component)SharedState.SubCategoryTabs).transform.Find("Content");
			if ((Object)(object)val != (Object)null)
			{
				for (int num = val.childCount - 1; num >= 0; num--)
				{
					Object.Destroy((Object)(object)((Component)val.GetChild(num)).gameObject);
				}
			}
			SharedState.SubCategoryTabEntries.Clear();
			ItemCategory[] subCategories = CategorySystem.GetSubCategories(SharedState.CurrentMajorFilter);
			if (subCategories.Length != 0)
			{
				if (!SharedState.CurrentSubCategoryFilter.HasValue || !Array.Exists(subCategories, (ItemCategory c) => c == SharedState.CurrentSubCategoryFilter.Value))
				{
					SharedState.CurrentSubCategoryFilter = subCategories[0];
				}
				foreach (ItemCategory itemCategory in subCategories)
				{
					AddSubCategoryTab(SharedState.SubCategoryTabs, CategorySystem.GetCategoryLabel(itemCategory), itemCategory, 170f);
				}
				UpdateSubCategoryTabs();
			}
		}

		private static void AddSubCategoryTab(PeakHorizontalTabs tabs, string label, ItemCategory? category, float width)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			GameObject val = tabs.AddTab(label);
			if (TrySetupTabVisual(val, width, 40f, out Button button, out Image background, out Image selected, out PeakText labelText))
			{
				CategoryTab categoryTab = new CategoryTab(category, val, button, background, selected, labelText);
				SharedState.SubCategoryTabEntries.Add(categoryTab);
				((UnityEvent)button.onClick).AddListener((UnityAction)delegate
				{
					SharedState.CurrentSubCategoryFilter = category;
					UpdateSubCategoryTabs();
					VirtualList.MarkListDirty("Sub category changed");
					VirtualList.RefreshListIfNeeded(force: true);
				});
				ApplySubCategoryTabStyle(categoryTab, category == SharedState.CurrentSubCategoryFilter);
			}
		}

		private static bool TrySetupTabVisual(GameObject tab, float width, float height, out Button button, out Image background, out Image selected, out PeakText labelText)
		{
			button = null;
			background = null;
			selected = null;
			labelText = null;
			if ((Object)(object)tab == (Object)null)
			{
				return false;
			}
			LayoutElement val = tab.GetComponent<LayoutElement>();
			if ((Object)(object)val == (Object)null)
			{
				val = tab.AddComponent<LayoutElement>();
			}
			val.minWidth = width;
			val.preferredWidth = width;
			val.flexibleWidth = 0f;
			val.preferredHeight = height;
			button = tab.GetComponent<Button>();
			Transform obj = tab.transform.Find("Image");
			background = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null);
			Transform obj2 = tab.transform.Find("Selected");
			selected = ((obj2 != null) ? ((Component)obj2).GetComponent<Image>() : null);
			labelText = tab.GetComponentInChildren<PeakText>(true);
			if ((Object)(object)button == (Object)null || (Object)(object)background == (Object)null || (Object)(object)selected == (Object)null || (Object)(object)labelText == (Object)null)
			{
				return false;
			}
			((TMP_Text)labelText.TextMesh).fontStyle = (FontStyles)0;
			((TMP_Text)labelText.TextMesh).enableAutoSizing = false;
			((TMP_Text)labelText.TextMesh).fontSize = 18f;
			((TMP_Text)labelText.TextMesh).alignment = (TextAlignmentOptions)514;
			((Graphic)background).raycastTarget = true;
			((Graphic)selected).raycastTarget = false;
			((Graphic)labelText.TextMesh).raycastTarget = false;
			return true;
		}

		internal static void UpdateSubCategoryVisibility()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			bool flag = SharedState.CurrentMajorFilter != MajorCategory.All;
			if ((Object)(object)SharedState.SubCategoryTabsRoot != (Object)null)
			{
				SharedState.SubCategoryTabsRoot.SetActive(flag);
			}
			if ((Object)(object)SharedState.TopControlsRect != (Object)null)
			{
				SharedState.TopControlsRect.sizeDelta = new Vector2(SharedState.TopControlsRect.sizeDelta.x, flag ? 166f : 122f);
			}
			if ((Object)(object)SharedState.ListContainerRect != (Object)null)
			{
				SharedState.ListContainerRect.offsetMax = (flag ? new Vector2(-20f, -236f) : new Vector2(-20f, -192f));
			}
		}

		internal static void RefreshLanguageDependentContent(bool force = false)
		{
			int currentLanguageIndex = Localization.GetCurrentLanguageIndex();
			string text = Localization.GetText("TITLE");
			string text2 = Localization.GetText("SEARCH_PLACEHOLDER");
			string text3 = text + "|" + text2;
			bool flag = !string.Equals(text3, SharedState.LastLanguageMarker, StringComparison.Ordinal);
			if (force || flag)
			{
				SharedState.LastLanguageMarker = text3;
				Localization.LastRenderedLanguageIndex = currentLanguageIndex;
				if ((Object)(object)SharedState.HeaderTitleText != (Object)null)
				{
					((TMP_Text)SharedState.HeaderTitleText.TextMesh).text = text;
				}
				PeakMenuButton? closeMenuButton = SharedState.CloseMenuButton;
				if ((Object)(object)((closeMenuButton != null) ? ((PeakLocalizableElement)closeMenuButton).Text : null) != (Object)null)
				{
					((PeakLocalizableElement)SharedState.CloseMenuButton).Text.text = Localization.GetTextOrFallback("CLOSE_BUTTON", "Close");
				}
				if ((Object)(object)SharedState.SearchInput != (Object)null)
				{
					SharedState.SearchInput.SetPlaceholder(text2);
				}
				for (int i = 0; i < SharedState.MajorTabEntries.Count; i++)
				{
					MajorCategoryTab majorCategoryTab = SharedState.MajorTabEntries[i];
					((TMP_Text)majorCategoryTab.Label.TextMesh).text = CategorySystem.GetMajorCategoryLabel(majorCategoryTab.Category);
				}
				for (int j = 0; j < SharedState.SubCategoryTabEntries.Count; j++)
				{
					CategoryTab categoryTab = SharedState.SubCategoryTabEntries[j];
					string text4 = (categoryTab.Category.HasValue ? CategorySystem.GetCategoryLabel(categoryTab.Category.Value) : CategorySystem.GetAllSubCategoryLabel());
					((TMP_Text)categoryTab.Label.TextMesh).text = text4;
				}
				ItemLoader.RefreshItemDisplayNamesForCurrentLanguage(force: false, text3);
				VirtualList.MarkListDirty("Language changed");
			}
		}

		private static void UpdateSubCategoryTabs()
		{
			for (int i = 0; i < SharedState.SubCategoryTabEntries.Count; i++)
			{
				CategoryTab categoryTab = SharedState.SubCategoryTabEntries[i];
				bool selected = categoryTab.Category == SharedState.CurrentSubCategoryFilter;
				ApplySubCategoryTabStyle(categoryTab, selected);
			}
		}

		internal static void ApplyMajorTabStyle(MajorCategoryTab tab, bool selected)
		{
			//IL_0006: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0065: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)tab.Background).color = SharedState.TabInactiveBg;
			((Graphic)tab.Selected).color = SharedState.TabActiveBg;
			((Behaviour)tab.Selected).enabled = selected;
			((Graphic)tab.Label.TextMesh).color = (selected ? SharedState.TabActiveText : SharedState.TabInactiveText);
			ColorBlock colors = ((Selectable)tab.Button).colors;
			((ColorBlock)(ref colors)).normalColor = SharedState.TabInactiveBg;
			((ColorBlock)(ref colors)).highlightedColor = SharedState.TabHighlightedBg;
			((ColorBlock)(ref colors)).pressedColor = SharedState.TabPressedBg;
			((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor;
			((Selectable)tab.Button).colors = colors;
		}

		internal static void ApplySubCategoryTabStyle(CategoryTab tab, bool selected)
		{
			//IL_0006: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0065: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)tab.Background).color = SharedState.TabInactiveBg;
			((Graphic)tab.Selected).color = SharedState.TabActiveBg;
			((Behaviour)tab.Selected).enabled = selected;
			((Graphic)tab.Label.TextMesh).color = (selected ? SharedState.TabActiveText : SharedState.TabInactiveText);
			ColorBlock colors = ((Selectable)tab.Button).colors;
			((ColorBlock)(ref colors)).normalColor = SharedState.TabInactiveBg;
			((ColorBlock)(ref colors)).highlightedColor = SharedState.TabHighlightedBg;
			((ColorBlock)(ref colors)).pressedColor = SharedState.TabPressedBg;
			((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor;
			((Selectable)tab.Button).colors = colors;
		}

		internal static void ResetState()
		{
			SharedState.MajorTabEntries.Clear();
			SharedState.SubCategoryTabEntries.Clear();
		}
	}
	internal static class UIBuilder
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__ClosePage;

			public static UnityAction<string> <1>__OnSearchChanged;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Func<GameObject, bool> <>9__5_0;

			public static Func<GameObject, bool> <>9__5_1;

			public static UnityAction <>9__8_0;

			public static UnityAction <>9__8_1;

			public static UnityAction<Vector2> <>9__8_2;

			public static Func<MethodInfo, bool> <>9__17_0;

			public static Func<MethodInfo, bool> <>9__17_1;

			internal bool <TryRecoverButtonTemplate>b__5_0(GameObject obj)
			{
				if ((Object)(object)obj != (Object)null)
				{
					return ((Object)obj).name == "UI_MainMenuButton_LeaveGame (2)";
				}
				return false;
			}

			internal bool <TryRecoverButtonTemplate>b__5_1(GameObject obj)
			{
				if ((Object)(object)obj != (Object)null)
				{
					return ((Object)obj).name.StartsWith("UI_MainMenuButton_LeaveGame", StringComparison.Ordinal);
				}
				return false;
			}

			internal void <BuildUI>b__8_0()
			{
				SharedState.PageOpen = true;
				TabsManager.RefreshLanguageDependentContent();
				ItemLoader.EnsureItemList();
				VirtualList.RefreshListIfNeeded();
			}

			internal void <BuildUI>b__8_1()
			{
				SharedState.PageOpen = false;
			}

			internal void <BuildUI>b__8_2(Vector2 _)
			{
				VirtualList.OnVirtualizedScrollChanged();
			}

			internal bool <ClosePage>b__17_0(MethodInfo m)
			{
				if (m.Name == "Close")
				{
					return m.GetParameters().Length == 0;
				}
				return false;
			}

			internal bool <ClosePage>b__17_1(MethodInfo m)
			{
				if (m.Name == "Close")
				{
					return m.GetParameters().Length == 1;
				}
				return false;
			}
		}

		private static bool _buttonTemplateRecovered;

		private static Scrollbar? _listScrollbar;

		private static MethodInfo? _menuWindowOpenMethod;

		private static MethodInfo? _menuWindowCloseMethod;

		internal static bool IsUIReady(out string reason)
		{
			List<string> list = new List<string>(3);
			InputCellMapper instance = SingletonAsset<InputCellMapper>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				list.Add("InputCellMapper.Instance == null");
			}
			else if ((Object)(object)instance.FloatSettingCell == (Object)null)
			{
				list.Add("InputCellMapper.FloatSettingCell == null");
			}
			if ((Object)(object)Templates.ButtonTemplate == (Object)null && !TryRecoverButtonTemplate(out string reason2))
			{
				if (string.IsNullOrWhiteSpace(reason2))
				{
					list.Add("Templates.ButtonTemplate == null");
				}
				else
				{
					list.Add("Templates.ButtonTemplate == null (" + reason2 + ")");
				}
			}
			if (list.Count == 0)
			{
				reason = string.Empty;
				return true;
			}
			reason = string.Join(", ", list);
			return false;
		}

		private static bool TryRecoverButtonTemplate(out string reason)
		{
			reason = string.Empty;
			if ((Object)(object)Templates.ButtonTemplate != (Object)null)
			{
				return true;
			}
			try
			{
				GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
				if (array == null || array.Length == 0)
				{
					reason = "Resources empty";
					return false;
				}
				GameObject val = ((IEnumerable<GameObject>)array).FirstOrDefault((Func<GameObject, bool>)((GameObject obj) => (Object)(object)obj != (Object)null && ((Object)obj).name == "UI_MainMenuButton_LeaveGame (2)"));
				if ((Object)(object)val == (Object)null)
				{
					val = ((IEnumerable<GameObject>)array).FirstOrDefault((Func<GameObject, bool>)((GameObject obj) => (Object)(object)obj != (Object)null && ((Object)obj).name.StartsWith("UI_MainMenuBu