Decompiled source of ItemBrowser v0.2.4
plugins/com.github.cherrycove.ItemBrowser.dll
Decompiled 15 hours ago
The result has been truncated due to the large size, download it to view full contents!
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