Decompiled source of MoreHeadBridge v2.2.0

MoreHeadBridge.dll

Decompiled 2 weeks 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 System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Photon.Pun;
using REPOLib;
using REPOLib.Modules;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Xuaun")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Registers MoreHead .hhh cosmetics into the vanilla REPO cosmetics system via REPOLib.")]
[assembly: AssemblyFileVersion("2.2.0.0")]
[assembly: AssemblyInformationalVersion("2.2.0+d5ea3830f0322aae515765e2e2c6866d4975638b")]
[assembly: AssemblyProduct("MoreHeadBridge")]
[assembly: AssemblyTitle("MoreHeadBridge")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.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 MoreHeadBridge
{
	internal static class BceConsole
	{
		private static readonly MethodInfo? _writeLine;

		private static readonly MethodInfo? _write;

		internal static bool IsAvailable => _writeLine != null;

		static BceConsole()
		{
			Type type = Type.GetType("BCE.console, BCE");
			if (!(type == null))
			{
				_writeLine = type.GetMethod("WriteLine", new Type[2]
				{
					typeof(string),
					typeof(ConsoleColor)
				});
				_write = type.GetMethod("Write", new Type[2]
				{
					typeof(string),
					typeof(ConsoleColor)
				});
			}
		}

		internal static void WriteLine(string msg, ConsoleColor color)
		{
			_writeLine?.Invoke(null, new object[2] { msg, color });
		}

		internal static void Write(string msg, ConsoleColor color)
		{
			_write?.Invoke(null, new object[2] { msg, color });
		}
	}
	internal static class BridgeIds
	{
		internal const string Prefix = "morehead-bridge:";

		internal static bool IsBridgeAsset(string? assetId)
		{
			if (!string.IsNullOrEmpty(assetId))
			{
				return assetId.StartsWith("morehead-bridge:", StringComparison.Ordinal);
			}
			return false;
		}

		internal static bool IsBridgeAsset(CosmeticAsset? asset)
		{
			if ((Object)(object)asset != (Object)null)
			{
				return IsBridgeAsset(asset.assetId);
			}
			return false;
		}
	}
	internal static class HhhCosmeticLoader
	{
		internal static readonly List<string> RegisteredAssetIds = new List<string>();

		internal static readonly HashSet<string> WorldAssetIds = new HashSet<string>();

		internal static readonly Dictionary<string, Texture2D> BridgeIconTextures = new Dictionary<string, Texture2D>();

		private static readonly Dictionary<string, CosmeticType> TagToType = new Dictionary<string, CosmeticType>
		{
			["head"] = (CosmeticType)0,
			["neck"] = (CosmeticType)30,
			["body"] = (CosmeticType)20,
			["hip"] = (CosmeticType)21,
			["rightarm"] = (CosmeticType)1,
			["leftarm"] = (CosmeticType)2,
			["rightleg"] = (CosmeticType)3,
			["leftleg"] = (CosmeticType)4,
			["world"] = (CosmeticType)0
		};

		private static readonly HashSet<string> ValidTags;

		private static readonly HashSet<string> _usedPrefabIds;

		private static readonly HashSet<string> _usedInternalNames;

		private static bool _moreHeadFixDone;

		private static readonly Dictionary<string, OverrideCosmeticType> _originalTypes;

		private static readonly Dictionary<string, OverrideCosmeticType> TagToOverrideType;

		public static void LoadAll()
		{
			string pluginPath = Paths.PluginPath;
			string[] files = Directory.GetFiles(pluginPath, "*.hhh", SearchOption.AllDirectories);
			string text = Plugin.SpecificFolders.Value ?? "";
			if (!string.IsNullOrWhiteSpace(text))
			{
				char[] invalidChars = Path.GetInvalidPathChars();
				string[] array = (from s in (from s in text.Split(',')
						select s.Trim() into s
						where s.Length > 0
						select s).Select(delegate(string s)
					{
						string text2 = new string(s.Where((char c) => !invalidChars.Contains(c)).ToArray());
						if (text2 != s)
						{
							Plugin.Logger.LogWarning((object)("SpecificFolders: '" + s + "' contained invalid path characters — changed to '" + text2 + "'."));
						}
						return text2;
					})
					where s.Length > 0
					select s).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToArray();
				string[] matched = array.Where((string a) => files.Any((string f) => f.IndexOf(a, StringComparison.OrdinalIgnoreCase) >= 0)).ToArray();
				string[] array2 = array.Except<string>(matched, StringComparer.OrdinalIgnoreCase).ToArray();
				if (matched.Length == 0)
				{
					Plugin.Logger.LogWarning((object)("SpecificFolders: none of the specified folders were found (" + string.Join(", ", array) + "). Loading all .hhh files instead."));
				}
				else
				{
					if (array2.Length != 0)
					{
						Plugin.Logger.LogWarning((object)("SpecificFolders: folder(s) not found and skipped: " + string.Join(", ", array2) + "."));
					}
					int num = files.Length;
					files = files.Where((string f) => matched.Any((string a) => f.IndexOf(a, StringComparison.OrdinalIgnoreCase) >= 0)).ToArray();
					LogInfo(string.Format("SpecificFolders: loaded from {0} — kept {1}/{2} files.", string.Join(", ", matched), files.Length, num));
				}
			}
			LogInfo($"Found {files.Length} .hhh file(s). Translating cosmetics from MoreHead to Vanilla REPO...");
			int num2 = 0;
			string[] array3 = files;
			foreach (string path in array3)
			{
				if (TryRegister(path))
				{
					num2++;
				}
			}
			int num3 = files.Length;
			int num4 = num3 - num2;
			LogInfo($"Done — {num2}/{num3} registered, {num4} error(s).");
		}

		private static bool TryRegister(string path)
		{
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			FileInfo fileInfo = new FileInfo(path);
			if (!fileInfo.Exists || fileInfo.Length < 1024)
			{
				Plugin.Logger.LogWarning((object)("Skipped (too small/missing): " + Path.GetFileName(path)));
				return false;
			}
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
			ParseFileName(fileNameWithoutExtension, out string name, out string tag);
			if (!TagToType.TryGetValue(tag, out var value))
			{
				return false;
			}
			AssetBundle val = AssetBundle.LoadFromFile(path);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogError((object)("Failed to load bundle: " + fileNameWithoutExtension));
				return false;
			}
			GameObject val2 = null;
			string[] allAssetNames = val.GetAllAssetNames();
			foreach (string text in allAssetNames)
			{
				GameObject val3 = val.LoadAsset<GameObject>(text);
				if ((Object)(object)val3 != (Object)null)
				{
					val2 = val3;
					break;
				}
			}
			val.Unload(false);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Logger.LogError((object)("No GameObject in bundle: " + fileNameWithoutExtension));
				return false;
			}
			if (Plugin.FixBridgedCosmetics.Value)
			{
				FixPrefab(val2, fileNameWithoutExtension);
			}
			string name2 = ((Object)val2).name;
			((Object)val2).name = EnsureUniqueId(name2, _usedPrefabIds);
			if (((Object)val2).name != name2)
			{
				Plugin.Logger.LogWarning((object)("Duplicate prefab name '" + name2 + "' → renamed to '" + ((Object)val2).name + "'"));
			}
			string text2 = name;
			name = EnsureUniqueId(name, _usedInternalNames);
			if (name != text2)
			{
				Plugin.Logger.LogWarning((object)("Duplicate internal name '" + text2 + "' → renamed to '" + name + "'"));
			}
			Cosmetic val4 = val2.GetComponent<Cosmetic>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = val2.AddComponent<Cosmetic>();
			}
			val4.type = value;
			PrefabRef val5 = NetworkPrefabs.RegisterNetworkPrefab("Cosmetics/" + ((Object)val2).name, val2);
			if (val5 == null)
			{
				Plugin.Logger.LogError((object)("Failed to register network prefab: " + name));
				return false;
			}
			string text3 = "morehead-bridge:" + name.ToLowerInvariant();
			CosmeticAsset val6 = ScriptableObject.CreateInstance<CosmeticAsset>();
			((Object)val6).name = name;
			val6.assetName = ((Object)val2).name;
			val6.type = value;
			val6.prefab = val5;
			val6.assetId = text3;
			val6.rarity = Plugin.DefaultRarity.Value;
			val6.customTypeList = new List<Type>();
			val6.tintable = false;
			if (TagToOverrideType.TryGetValue(tag, out var value2))
			{
				_originalTypes[text3] = value2;
			}
			PerCosmeticOverrides.ApplyIfPresent(val6);
			Cosmetics.RegisterCosmetic(val6);
			RegisteredAssetIds.Add(text3);
			if (tag == "world")
			{
				WorldAssetIds.Add(text3);
			}
			Texture2D val7 = TryExtractIconTexture(val2);
			if ((Object)(object)val7 != (Object)null)
			{
				BridgeIconTextures[text3] = val7;
			}
			return true;
		}

		private static Texture2D? TryExtractIconTexture(GameObject prefab)
		{
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			string[] array = new string[5] { "_MainTex", "_BaseMap", "_BaseColorMap", "_Albedo", "_AlbedoMap" };
			Renderer[] array2 = componentsInChildren;
			foreach (Renderer val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				foreach (Material val2 in sharedMaterials)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					string[] array3 = array;
					foreach (string text in array3)
					{
						if (val2.HasProperty(text))
						{
							Texture texture = val2.GetTexture(text);
							Texture2D val3 = (Texture2D)(object)((texture is Texture2D) ? texture : null);
							if (val3 != null && (Object)(object)val3 != (Object)null)
							{
								return val3;
							}
						}
					}
				}
			}
			return null;
		}

		private static void ParseFileName(string fileName, out string name, out string tag)
		{
			int num = fileName.LastIndexOf('_');
			if (num >= 0)
			{
				int num2 = num + 1;
				string text = fileName.Substring(num2, fileName.Length - num2).ToLowerInvariant();
				if (ValidTags.Contains(text))
				{
					name = fileName.Substring(0, num);
					tag = text;
					return;
				}
			}
			name = fileName;
			tag = "head";
		}

		private static string EnsureUniqueId(string baseName, HashSet<string> used)
		{
			string text = baseName;
			int num = 1;
			while (!used.Add(text))
			{
				text = $"{baseName}({num})";
				num++;
			}
			return text;
		}

		private static void LogInfo(string msg)
		{
			if (BceConsole.IsAvailable)
			{
				BceConsole.WriteLine("[Info   :  MoreHead Bridge] " + msg, ConsoleColor.Cyan);
			}
			else
			{
				Plugin.Logger.LogInfo((object)(msg ?? ""));
			}
		}

		internal static bool IsWorldAsset(CosmeticAsset? asset)
		{
			if ((Object)(object)asset != (Object)null && BridgeIds.IsBridgeAsset(asset))
			{
				return WorldAssetIds.Contains(asset.assetId);
			}
			return false;
		}

		internal static void ReapplyDefaultRarityToAll()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)MetaManager.instance == (Object)null)
			{
				return;
			}
			Rarity value = Plugin.DefaultRarity.Value;
			foreach (CosmeticAsset cosmeticAsset in MetaManager.instance.cosmeticAssets)
			{
				if (!((Object)(object)cosmeticAsset == (Object)null) && BridgeIds.IsBridgeAsset(cosmeticAsset) && (!PerCosmeticOverrides.TryGet(cosmeticAsset.assetId, out CosmeticOverrideData data) || !data.Rarity.HasValue))
				{
					cosmeticAsset.rarity = value;
				}
			}
			if (Plugin.FixBridgedCosmetics.Value && !_moreHeadFixDone)
			{
				_moreHeadFixDone = true;
				TryFixMoreHeadPrefabs();
			}
		}

		private static void FixPrefab(GameObject prefab, string label = "", Type? partShrinkerType = null, bool verbose = true)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Invalid comparison between Unknown and I4
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				num++;
				try
				{
					Object.DestroyImmediate((Object)(object)val);
				}
				catch
				{
					try
					{
						val.enabled = false;
					}
					catch
					{
					}
				}
			}
			Rigidbody[] componentsInChildren2 = prefab.GetComponentsInChildren<Rigidbody>(true);
			foreach (Rigidbody val2 in componentsInChildren2)
			{
				num2++;
				try
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
				catch
				{
					try
					{
						val2.isKinematic = true;
						val2.useGravity = false;
					}
					catch
					{
					}
				}
			}
			Animation[] componentsInChildren3 = prefab.GetComponentsInChildren<Animation>(true);
			foreach (Animation val3 in componentsInChildren3)
			{
				if ((Object)(object)val3.clip != (Object)null && (int)val3.clip.wrapMode != 2)
				{
					val3.clip.wrapMode = (WrapMode)2;
					num3++;
				}
				val3.wrapMode = (WrapMode)2;
			}
			Animator[] componentsInChildren4 = prefab.GetComponentsInChildren<Animator>(true);
			foreach (Animator val4 in componentsInChildren4)
			{
				if ((Object)(object)val4.runtimeAnimatorController == (Object)null)
				{
					continue;
				}
				bool flag = false;
				AnimationClip[] animationClips = val4.runtimeAnimatorController.animationClips;
				foreach (AnimationClip val5 in animationClips)
				{
					if ((Object)(object)val5 != (Object)null && !((Motion)val5).isLooping)
					{
						flag = true;
						break;
					}
				}
				if (flag && (Object)(object)((Component)val4).GetComponent<AnimatorLooper>() == (Object)null)
				{
					((Component)val4).gameObject.AddComponent<AnimatorLooper>();
					num4++;
				}
			}
			string text = (string.IsNullOrEmpty(label) ? ((Object)prefab).name : label);
			if (num > 0 || num2 > 0 || num3 > 0 || num4 > 0)
			{
				string text2 = "'" + text + "': " + $"removed {num} Collider(s), {num2} Rigidbody(s); " + $"looped {num3} Animation clip(s), {num4} Animator(s).";
				if (verbose)
				{
					Plugin.Logger.LogInfo((object)text2);
				}
				else
				{
					Plugin.Logger.LogDebug((object)text2);
				}
			}
			Type type = partShrinkerType ?? FindPartShrinkerType();
			if (type != null)
			{
				Component[] componentsInChildren5 = prefab.GetComponentsInChildren(type, true);
				if (componentsInChildren5.Length != 0)
				{
					string text3 = $"'{text}': {componentsInChildren5.Length} component(s) — body-part hiding active.";
					if (verbose)
					{
						Plugin.Logger.LogInfo((object)text3);
					}
					else
					{
						Plugin.Logger.LogDebug((object)text3);
					}
				}
				return;
			}
			int num5 = 0;
			MonoBehaviour[] componentsInChildren6 = prefab.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val6 in componentsInChildren6)
			{
				if ((Object)(object)val6 == (Object)null)
				{
					num5++;
				}
			}
			if (num5 > 0)
			{
				Plugin.Logger.LogWarning((object)($"'{text}': {num5} missing script(s) detected — " + "install MoreHeadUtilities if body-part hiding is needed."));
			}
		}

		private static Type? FindPartShrinkerType()
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				if (assembly.GetName().Name == "MoreHeadUtilities")
				{
					return assembly.GetType("MoreHeadUtilities.PartShrinker");
				}
			}
			return null;
		}

		private static void TryFixMoreHeadPrefabs()
		{
			try
			{
				Type type = Type.GetType("MoreHead.HeadDecorationManager, MoreHead");
				if (type == null)
				{
					return;
				}
				PropertyInfo property = type.GetProperty("Decorations", BindingFlags.Static | BindingFlags.Public);
				if (property == null || !(property.GetValue(null) is IList list) || list.Count == 0)
				{
					return;
				}
				PropertyInfo property2 = list[0].GetType().GetProperty("Prefab");
				if (property2 == null)
				{
					return;
				}
				Type partShrinkerType = FindPartShrinkerType();
				int num = 0;
				foreach (object item in list)
				{
					object? value = property2.GetValue(item);
					GameObject val = (GameObject)((value is GameObject) ? value : null);
					if (val != null)
					{
						FixPrefab(val, "", partShrinkerType, verbose: false);
						num++;
					}
				}
				Plugin.Logger.LogInfo((object)$"Applied fixes to {num} bridged cosmetics.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogDebug((object)("Bridged cosmetic pass skipped: " + ex.Message));
			}
		}

		internal static void ReapplyDefaults(CosmeticAsset asset)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			asset.rarity = Plugin.DefaultRarity.Value;
			if (_originalTypes.TryGetValue(asset.assetId, out var value))
			{
				(CosmeticType cosmeticType, bool isWorld) tuple = PerCosmeticOverrides.ResolveType(value);
				CosmeticType item = tuple.cosmeticType;
				bool item2 = tuple.isWorld;
				asset.type = item;
				if (item2)
				{
					WorldAssetIds.Add(asset.assetId);
				}
				else
				{
					WorldAssetIds.Remove(asset.assetId);
				}
			}
		}

		static HhhCosmeticLoader()
		{
			HashSet<string> hashSet = new HashSet<string>();
			foreach (string key in TagToType.Keys)
			{
				hashSet.Add(key);
			}
			ValidTags = hashSet;
			_usedPrefabIds = new HashSet<string>();
			_usedInternalNames = new HashSet<string>();
			_originalTypes = new Dictionary<string, OverrideCosmeticType>();
			TagToOverrideType = new Dictionary<string, OverrideCosmeticType>
			{
				["head"] = OverrideCosmeticType.Hat,
				["neck"] = OverrideCosmeticType.HeadBottom,
				["body"] = OverrideCosmeticType.BodyTop,
				["hip"] = OverrideCosmeticType.BodyBottom,
				["rightarm"] = OverrideCosmeticType.ArmRight,
				["leftarm"] = OverrideCosmeticType.ArmLeft,
				["rightleg"] = OverrideCosmeticType.LegRight,
				["leftleg"] = OverrideCosmeticType.LegLeft,
				["world"] = OverrideCosmeticType.World
			};
		}
	}
	internal static class BatchIconGenerator
	{
		[CompilerGenerated]
		private sealed class <Run>d__7 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private List<CosmeticAsset> <work>5__2;

			private bool <interrupted>5__3;

			private List<CosmeticAsset>.Enumerator <>7__wrap3;

			private CosmeticAsset <asset>5__5;

			private int <guard>5__6;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if ((uint)(num - -4) <= 1u || (uint)(num - 2) <= 2u)
				{
					try
					{
						if (num == -4 || (uint)(num - 2) <= 2u)
						{
							try
							{
							}
							finally
							{
								<>m__Finally2();
							}
						}
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<work>5__2 = null;
				<>7__wrap3 = default(List<CosmeticAsset>.Enumerator);
				<asset>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Expected O, but got Unknown
				//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d0: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						_didStartOnce = true;
						<>2__current = (object)new WaitForSecondsRealtime(0.5f);
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						if ((Object)(object)MetaManager.instance == (Object)null)
						{
							_isRunning = false;
							return false;
						}
						<work>5__2 = new List<CosmeticAsset>();
						foreach (CosmeticAsset cosmeticAsset in MetaManager.instance.cosmeticAssets)
						{
							if (!((Object)(object)cosmeticAsset == (Object)null) && cosmeticAsset.assetId != null && BridgeIds.IsBridgeAsset(cosmeticAsset) && !IconCapture.HasCache(cosmeticAsset))
							{
								<work>5__2.Add(cosmeticAsset);
							}
						}
						Plugin.Logger.LogInfo((object)$"GenerateAllIcons: {<work>5__2.Count} icon(s) to generate.");
						if (<work>5__2.Count == 0)
						{
							_isRunning = false;
							Plugin.GenerateAllIcons.Value = false;
							((BaseUnityPlugin)Plugin.Instance).Config.Save();
							return false;
						}
						_progressDone = 0;
						_progressFailed = 0;
						_progressTotal = <work>5__2.Count;
						<interrupted>5__3 = true;
						<>1__state = -3;
						<>7__wrap3 = <work>5__2.GetEnumerator();
						<>1__state = -4;
						goto IL_03a4;
					case 2:
						<>1__state = -4;
						<guard>5__6 = 0;
						goto IL_02af;
					case 3:
						<>1__state = -4;
						<guard>5__6++;
						goto IL_02af;
					case 4:
						{
							<>1__state = -4;
							if ((Object)(object)MetaManager.instance == (Object)null)
							{
								break;
							}
							if (IconCapture.TryCapture(<asset>5__5))
							{
								_progressDone++;
							}
							else
							{
								_progressFailed++;
							}
							MetaManager.instance.CosmeticPreviewSet(false);
							MetaManager.instance.CosmeticPlayerUpdateLocal(false, false);
							WorldCosmeticsSetupPatch.SetAllWorldInstancesActive(active: true);
							int num = _progressDone + _progressFailed;
							if (num % 50 == 0)
							{
								Plugin.Logger.LogInfo((object)($"Batch progress: {num}/{<work>5__2.Count} " + $"({_progressDone} ok, {_progressFailed} failed)"));
							}
							<asset>5__5 = null;
							goto IL_03a4;
						}
						IL_03a4:
						while (<>7__wrap3.MoveNext())
						{
							<asset>5__5 = <>7__wrap3.Current;
							if ((Object)(object)MetaManager.instance == (Object)null)
							{
								break;
							}
							int num2 = MetaManager.instance.cosmeticAssets.IndexOf(<asset>5__5);
							if (num2 < 0)
							{
								_progressFailed++;
								continue;
							}
							MetaManager.instance.cosmeticEquippedPreview.Clear();
							MetaManager.instance.cosmeticEquippedPreview.Add(num2);
							if (MetaManager.instance.colorsEquipped != null)
							{
								MetaManager.instance.colorsEquippedPreview = (int[])MetaManager.instance.colorsEquipped.Clone();
							}
							MetaManager.instance.CosmeticPreviewSet(true);
							MetaManager.instance.CosmeticPlayerUpdateLocal(false, false);
							WorldCosmeticsSetupPatch.SetAllWorldInstancesActive(active: false);
							if (HhhCosmeticLoader.IsWorldAsset(<asset>5__5))
							{
								WorldCosmeticsSetupPatch.SetWorldAssetActive(<asset>5__5, active: true);
							}
							SkipEquipAnimationFor(<asset>5__5);
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						break;
						IL_02af:
						if (<guard>5__6 < 3 && !IsAnimComplete(<asset>5__5))
						{
							<>2__current = null;
							<>1__state = 3;
							return true;
						}
						<>2__current = (object)new WaitForEndOfFrame();
						<>1__state = 4;
						return true;
					}
					<>m__Finally2();
					<>7__wrap3 = default(List<CosmeticAsset>.Enumerator);
					<interrupted>5__3 = false;
					<>m__Finally1();
					Plugin.GenerateAllIcons.Value = false;
					((BaseUnityPlugin)Plugin.Instance).Config.Save();
					Plugin.Logger.LogInfo((object)($"GenerateAllIcons done — {_progressDone} captured, " + $"{_progressFailed} failed. Flag reset to false."));
					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;
				if (_isRunning)
				{
					_isRunning = false;
					if (<interrupted>5__3)
					{
						int num = _progressTotal - _progressDone - _progressFailed;
						Plugin.Logger.LogWarning((object)("GenerateAllIcons: batch interrupted at " + $"{_progressDone + _progressFailed}/{_progressTotal} " + $"({num} still to go). " + "Reopen the menu to continue."));
					}
				}
				if ((Object)(object)MetaManager.instance != (Object)null)
				{
					MetaManager.instance.CosmeticPreviewSet(false);
					MetaManager.instance.CosmeticPlayerUpdateLocal(false, false);
				}
				WorldCosmeticsSetupPatch.SetAllWorldInstancesActive(active: true);
			}

			private void <>m__Finally2()
			{
				<>1__state = -3;
				((IDisposable)<>7__wrap3).Dispose();
			}

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

		private static bool _isRunning;

		private static bool _didStartOnce;

		private static int _progressDone;

		private static int _progressFailed;

		private static int _progressTotal;

		private static FieldInfo? _iconCreationAvatarField;

		private static FieldInfo? _equipLerpField;

		internal static void TryStart(MonoBehaviour host)
		{
			if (!_isRunning && Plugin.GenerateAllIcons.Value)
			{
				if (_didStartOnce)
				{
					Plugin.Logger.LogWarning((object)"GenerateAllIcons: previous batch was interrupted. Resuming — only icons still missing will be generated.");
				}
				_isRunning = true;
				host.StartCoroutine(Run());
			}
		}

		internal static void NotifyMenuClosed()
		{
			if (_isRunning)
			{
				_isRunning = false;
				int num = _progressTotal - _progressDone - _progressFailed;
				Plugin.Logger.LogWarning((object)("GenerateAllIcons: batch interrupted at " + $"{_progressDone + _progressFailed}/{_progressTotal} " + $"({num} still to go). " + "Reopen the menu to continue. (Your equipped cosmetics were not modified.)"));
			}
		}

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

		private static void SkipEquipAnimationFor(CosmeticAsset asset)
		{
			if ((object)_iconCreationAvatarField == null)
			{
				_iconCreationAvatarField = AccessTools.Field(typeof(Cosmetic), "iconCreationAvatar");
			}
			if (_iconCreationAvatarField == null)
			{
				return;
			}
			Cosmetic[] array = Object.FindObjectsOfType<Cosmetic>();
			foreach (Cosmetic val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.cosmeticAsset == (Object)(object)asset)
				{
					_iconCreationAvatarField.SetValue(val, true);
				}
			}
		}

		private static bool IsAnimComplete(CosmeticAsset asset)
		{
			if ((object)_equipLerpField == null)
			{
				_equipLerpField = AccessTools.Field(typeof(Cosmetic), "equipLerp");
			}
			if (_equipLerpField == null)
			{
				return true;
			}
			Cosmetic[] array = Object.FindObjectsOfType<Cosmetic>();
			foreach (Cosmetic val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.cosmeticAsset == (Object)(object)asset && (float)(_equipLerpField.GetValue(val) ?? ((object)1f)) < 1f)
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(MenuPageCosmetics), "Start")]
	internal static class BatchIconGeneratorStartPatch
	{
		[HarmonyPostfix]
		private static void Postfix(MenuPageCosmetics __instance)
		{
			BatchIconGenerator.TryStart((MonoBehaviour)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(MenuPageCosmetics), "OnDestroy")]
	internal static class BatchIconGeneratorMenuClosePatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			BatchIconGenerator.NotifyMenuClosed();
			CosmeticHoverPatch.OnMenuClosed();
			CosmeticsMenuState.OnMenuClosed();
			CosmeticsMenuLateUpdatePatch.OnMenuClosed();
		}
	}
	internal static class FavHideIcons
	{
		private const string ResourcePrefix = "MoreHeadBridge.Icons.Resources.";

		private static Sprite? _star;

		private static Sprite? _hide;

		internal static Sprite? StarSprite => _star ?? (_star = LoadSprite("star.png"));

		internal static Sprite? HideSprite => _hide ?? (_hide = LoadSprite("hide.png"));

		private static Sprite? LoadSprite(string fileName)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = "MoreHeadBridge.Icons.Resources." + fileName;
				using Stream stream = typeof(FavHideIcons).Assembly.GetManifestResourceStream(text);
				if (stream == null)
				{
					Plugin.Logger.LogWarning((object)("FavHideIcons: embedded resource '" + text + "' not found."));
					return null;
				}
				byte[] array = new byte[stream.Length];
				for (int i = 0; i < array.Length; i += stream.Read(array, i, array.Length - i))
				{
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				((Object)val).name = "MoreHeadBridge_" + fileName;
				((Texture)val).filterMode = (FilterMode)1;
				if (!ImageConversion.LoadImage(val, array))
				{
					Plugin.Logger.LogWarning((object)("FavHideIcons: Texture2D.LoadImage failed for '" + text + "'."));
					return null;
				}
				MaskWhitePixels(val);
				Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width);
				((Object)val2).name = "MoreHeadBridge_" + fileName;
				return val2;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("FavHideIcons: error loading '" + fileName + "': " + ex.Message));
				return null;
			}
		}

		private static void MaskWhitePixels(Texture2D tex)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Color32[] pixels = tex.GetPixels32();
			for (int i = 0; i < pixels.Length; i++)
			{
				Color32 val = pixels[i];
				if (val.r > 220 && val.g > 220 && val.b > 220)
				{
					pixels[i].a = 0;
				}
			}
			tex.SetPixels32(pixels);
			tex.Apply();
		}
	}
	internal static class IconCacheCleaner
	{
		internal static void Run()
		{
			if (!Plugin.DeleteIconCache.Value)
			{
				return;
			}
			try
			{
				string cacheDir = IconCapture.CacheDir;
				if (!Directory.Exists(cacheDir))
				{
					Plugin.Logger.LogInfo((object)"DeleteIconCache: no cache directory, nothing to do.");
					ResetFlag();
					return;
				}
				string text = Plugin.DeleteIconsMatching.Value ?? "";
				string[] array = (from s in text.Split(',')
					select s.Trim().ToLowerInvariant() into s
					where s.Length > 0
					select s).ToArray();
				HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
				foreach (string registeredAssetId in HhhCosmeticLoader.RegisteredAssetIds)
				{
					int num = registeredAssetId.IndexOf(':');
					if (num >= 0 && num + 1 < registeredAssetId.Length)
					{
						string text2 = registeredAssetId;
						int num2 = num + 1;
						hashSet.Add(text2.Substring(num2, text2.Length - num2));
					}
				}
				int num3 = 0;
				int num4 = 0;
				string[] files = Directory.GetFiles(cacheDir, "*.png");
				foreach (string text3 in files)
				{
					string name = Path.GetFileNameWithoutExtension(text3).ToLowerInvariant();
					if (!hashSet.Contains(name))
					{
						num4++;
						continue;
					}
					if (array.Length != 0 && !array.Any((string f) => name.Contains(f)))
					{
						num4++;
						continue;
					}
					try
					{
						File.Delete(text3);
						num3++;
					}
					catch (Exception ex)
					{
						Plugin.Logger.LogWarning((object)("Failed to delete '" + text3 + "': " + ex.Message));
					}
				}
				Plugin.Logger.LogInfo((object)($"DeleteIconCache: removed {num3} bridge icon(s), kept {num4}. " + "Filter: " + ((array.Length == 0) ? "(all bridge icons)" : string.Join(",", array))));
			}
			catch (Exception ex2)
			{
				Plugin.Logger.LogError((object)("DeleteIconCache failed: " + ex2.Message));
			}
			finally
			{
				ResetFlag();
			}
		}

		private static void ResetFlag()
		{
			Plugin.DeleteIconCache.Value = false;
			((BaseUnityPlugin)Plugin.Instance).Config.Save();
		}
	}
	internal static class IconCapture
	{
		private const int OutSize = 128;

		private static string? _cacheDir;

		private static FieldInfo? _renderTextureInstanceField;

		private static readonly Rect CropHead = new Rect(0.22f, 0.62f, 0.56f, 0.35f);

		private static readonly Rect CropNeck = new Rect(0.22f, 0.5f, 0.56f, 0.38f);

		private static readonly Rect CropBody = new Rect(0.18f, 0.34f, 0.64f, 0.36f);

		private static readonly Rect CropArmR = new Rect(0.05f, 0.3f, 0.5f, 0.4f);

		private static readonly Rect CropArmL = new Rect(0.45f, 0.3f, 0.5f, 0.4f);

		private static readonly Rect CropLegR = new Rect(0.1f, 0f, 0.45f, 0.45f);

		private static readonly Rect CropLegL = new Rect(0.45f, 0f, 0.45f, 0.45f);

		private static readonly Rect CropFull = new Rect(0f, 0f, 1f, 1f);

		internal static string CacheDir
		{
			get
			{
				if (_cacheDir != null)
				{
					return _cacheDir;
				}
				_cacheDir = Path.Combine(Application.persistentDataPath, "Cache", "Icons", "CosmeticsModded", "MoreHeadBridge_CosmeticsIcons");
				MigrateLegacyCache(_cacheDir);
				return _cacheDir;
			}
		}

		private static void MigrateLegacyCache(string newDir)
		{
			string path = Path.Combine(Application.persistentDataPath, "MoreHeadBridge_Icons");
			if (!Directory.Exists(path))
			{
				return;
			}
			Plugin.Logger.LogInfo((object)"IconCapture: migrating icon cache from legacy location...");
			try
			{
				Directory.CreateDirectory(newDir);
				int num = 0;
				int num2 = 0;
				string[] files = Directory.GetFiles(path, "*.png");
				foreach (string text in files)
				{
					string text2 = Path.Combine(newDir, Path.GetFileName(text));
					try
					{
						if (!File.Exists(text2))
						{
							File.Move(text, text2);
						}
						else
						{
							File.Delete(text);
						}
						num++;
					}
					catch (Exception ex)
					{
						num2++;
						Plugin.Logger.LogWarning((object)("IconCapture: could not migrate '" + Path.GetFileName(text) + "': " + ex.Message));
					}
				}
				try
				{
					if (Directory.GetFiles(path).Length == 0)
					{
						Directory.Delete(path, recursive: false);
					}
				}
				catch
				{
				}
				Plugin.Logger.LogInfo((object)$"IconCapture: cache migration done — {num} moved, {num2} failed.");
			}
			catch (Exception ex2)
			{
				Plugin.Logger.LogWarning((object)("IconCapture: cache migration failed: " + ex2.Message));
			}
		}

		internal static string CachePathFor(CosmeticAsset asset)
		{
			string text = ((Object)asset).name.Replace("(Clone)", "").ToLowerInvariant();
			return Path.Combine(CacheDir, text + ".png");
		}

		internal static bool HasCache(CosmeticAsset asset)
		{
			return File.Exists(CachePathFor(asset));
		}

		private static RenderTexture? FindActiveAvatarRT()
		{
			PlayerAvatarMenuHover val = Object.FindObjectOfType<PlayerAvatarMenuHover>();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			if ((object)_renderTextureInstanceField == null)
			{
				_renderTextureInstanceField = AccessTools.Field(typeof(PlayerAvatarMenuHover), "renderTextureInstance");
			}
			if (_renderTextureInstanceField == null)
			{
				Plugin.Logger.LogWarning((object)"IconCapture: PlayerAvatarMenuHover.renderTextureInstance not found — update MoreHeadBridge.");
			}
			else
			{
				object? value = _renderTextureInstanceField.GetValue(val);
				RenderTexture val2 = (RenderTexture)((value is RenderTexture) ? value : null);
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
			}
			RawImage component = ((Component)val).GetComponent<RawImage>();
			if (!((Object)(object)component != (Object)null))
			{
				return null;
			}
			Texture texture = component.texture;
			return (RenderTexture?)(object)((texture is RenderTexture) ? texture : null);
		}

		internal static bool TryCapture(CosmeticAsset asset)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return TryCapture(asset, (CosmeticType)(HhhCosmeticLoader.IsWorldAsset(asset) ? (-1) : ((asset != null) ? ((int)asset.type) : 0)));
		}

		internal static bool TryCapture(CosmeticAsset asset, CosmeticType type)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_007d: 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)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected O, but got Unknown
			if ((Object)(object)asset == (Object)null)
			{
				return false;
			}
			if (HasCache(asset))
			{
				return false;
			}
			Texture2D val = null;
			Texture2D val2 = null;
			Texture2D val3 = null;
			RenderTexture active = RenderTexture.active;
			try
			{
				RenderTexture val4 = FindActiveAvatarRT();
				if ((Object)(object)val4 == (Object)null)
				{
					return false;
				}
				Directory.CreateDirectory(CacheDir);
				RenderTexture.active = val4;
				val = new Texture2D(((Texture)val4).width, ((Texture)val4).height, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, (float)((Texture)val4).width, (float)((Texture)val4).height), 0, 0);
				val.Apply();
				Rect cropRect = GetCropRect(type);
				int num = Mathf.RoundToInt(((Rect)(ref cropRect)).x * (float)((Texture)val4).width);
				int num2 = Mathf.RoundToInt(((Rect)(ref cropRect)).y * (float)((Texture)val4).height);
				int num3 = Mathf.RoundToInt(((Rect)(ref cropRect)).width * (float)((Texture)val4).width);
				int num4 = Mathf.RoundToInt(((Rect)(ref cropRect)).height * (float)((Texture)val4).height);
				num3 = Mathf.Max(1, Mathf.Min(num3, ((Texture)val4).width - num));
				num4 = Mathf.Max(1, Mathf.Min(num4, ((Texture)val4).height - num2));
				Color[] pixels = val.GetPixels(num, num2, num3, num4);
				val2 = new Texture2D(num3, num4, (TextureFormat)4, false);
				val2.SetPixels(pixels);
				val2.Apply();
				val3 = ResizeBilinear(val2, 128, 128);
				File.WriteAllBytes(CachePathFor(asset), ImageConversion.EncodeToPNG(val3));
				if ((Object)(object)asset.icon != (Object)null)
				{
					Object.Destroy((Object)(object)asset.icon);
					asset.icon = null;
				}
				RefreshVisibleButtons(asset);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogDebug((object)("Icon capture failed for '" + ((Object)asset).name + "': " + ex.Message));
				return false;
			}
			finally
			{
				RenderTexture.active = active;
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
				if ((Object)(object)val3 != (Object)null)
				{
					Object.Destroy((Object)(object)val3);
				}
			}
		}

		private static Rect GetCropRect(CosmeticType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected I4, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			switch ((int)type)
			{
			case 0:
			case 5:
			case 14:
			case 15:
			case 17:
			case 18:
			case 24:
			case 31:
			case 32:
				return CropHead;
			case 6:
			case 25:
			case 30:
				return CropNeck;
			case 7:
			case 8:
			case 16:
			case 20:
			case 21:
			case 23:
				return CropBody;
			case 1:
			case 9:
			case 13:
			case 26:
				return CropArmR;
			case 2:
			case 10:
			case 27:
				return CropArmL;
			case 3:
			case 11:
			case 19:
			case 28:
				return CropLegR;
			case 4:
			case 12:
			case 22:
			case 29:
				return CropLegL;
			default:
				return CropFull;
			}
		}

		private static void RefreshVisibleButtons(CosmeticAsset asset)
		{
			try
			{
				MenuPageCosmetics val = Object.FindObjectOfType<MenuPageCosmetics>();
				MenuElementCosmeticButton[] array = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentsInChildren<MenuElementCosmeticButton>(true) : Object.FindObjectsOfType<MenuElementCosmeticButton>());
				MenuElementCosmeticButton[] array2 = array;
				foreach (MenuElementCosmeticButton val2 in array2)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)val2.cosmeticAsset == (Object)(object)asset)
					{
						val2.UpdateIcon(false);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogDebug((object)("Button refresh failed: " + ex.Message));
			}
		}

		private static Texture2D ResizeBilinear(Texture2D src, int w, int h)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			RenderTexture temporary = RenderTexture.GetTemporary(w, h);
			try
			{
				Graphics.Blit((Texture)(object)src, temporary);
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(w, h, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, (float)w, (float)h), 0, 0);
				val.Apply();
				RenderTexture.active = active;
				return val;
			}
			finally
			{
				RenderTexture.ReleaseTemporary(temporary);
			}
		}
	}
	internal static class PlaceholderIcon
	{
		private const int Size = 64;

		private static Sprite? _cached;

		internal static Sprite Get()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_cached != (Object)null)
			{
				return _cached;
			}
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			((Object)val).name = "MoreHeadBridge_Placeholder";
			((Texture)val).filterMode = (FilterMode)0;
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 0.8f, 0f, 1f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(0.13f, 0.13f, 0.18f, 1f);
			Color val4 = default(Color);
			((Color)(ref val4))..ctor(0.22f, 0.22f, 0.28f, 1f);
			Color val5 = default(Color);
			((Color)(ref val5))..ctor(1f, 0.8f, 0f, 0.35f);
			Color[] array = (Color[])(object)new Color[4096];
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					bool flag = j < 3 || j >= 61 || i < 3 || i >= 61;
					bool flag2 = (j + i) / 4 % 2 == 0;
					Color val6 = ((!flag) ? ((!flag2) ? val4 : Color.Lerp(val3, val5, 0.5f)) : val2);
					array[i * 64 + j] = val6;
				}
			}
			DrawM(array, 64, val2);
			val.SetPixels(array);
			val.Apply();
			_cached = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 64f);
			((Object)_cached).name = "MoreHeadBridge_Placeholder";
			return _cached;
		}

		private static void DrawM(Color[] pixels, int size, Color color)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 14; i <= 50; i++)
			{
				Plot(pixels, size, 18, i, color);
				Plot(pixels, size, 19, i, color);
				Plot(pixels, size, 45, i, color);
				Plot(pixels, size, 44, i, color);
			}
			int num = 24;
			for (int j = 0; j <= num; j++)
			{
				int y = 50 - j;
				int num2 = 18 + j * 13 / num;
				int num3 = 45 - j * 14 / num;
				Plot(pixels, size, num2, y, color);
				Plot(pixels, size, num2 + 1, y, color);
				Plot(pixels, size, num3, y, color);
				Plot(pixels, size, num3 - 1, y, color);
			}
		}

		private static void Plot(Color[] pixels, int size, int x, int y, Color color)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (x >= 0 && y >= 0 && x < size && y < size)
			{
				pixels[y * size + x] = color;
			}
		}
	}
	internal static class BridgeFavoritesManager
	{
		private sealed class SaveData
		{
			public List<string> Favorites { get; set; } = new List<string>();


			public List<string> Hidden { get; set; } = new List<string>();

		}

		private static readonly HashSet<string> _favorites = new HashSet<string>();

		private static readonly HashSet<string> _hidden = new HashSet<string>();

		private static bool _loaded;

		private static readonly string SavePath = Path.Combine(Paths.ConfigPath, "MoreHeadBridge_Favorites.json");

		private static Task _lastWrite = Task.CompletedTask;

		internal static void EnsureLoaded()
		{
			if (!_loaded)
			{
				_loaded = true;
				Load();
			}
		}

		internal static bool IsFavorite(CosmeticAsset? asset)
		{
			if ((Object)(object)asset != (Object)null)
			{
				return _favorites.Contains(KeyFor(asset));
			}
			return false;
		}

		internal static bool IsHidden(CosmeticAsset? asset)
		{
			if ((Object)(object)asset != (Object)null)
			{
				return _hidden.Contains(KeyFor(asset));
			}
			return false;
		}

		internal static bool HasAnyFavorite()
		{
			return _favorites.Count > 0;
		}

		internal static bool HasAnyHidden()
		{
			return _hidden.Count > 0;
		}

		internal static bool ToggleFavorite(CosmeticAsset asset)
		{
			string item = KeyFor(asset);
			if (_favorites.Remove(item))
			{
				Save();
				return false;
			}
			_hidden.Remove(item);
			_favorites.Add(item);
			Save();
			return true;
		}

		internal static bool ToggleHidden(CosmeticAsset asset)
		{
			string item = KeyFor(asset);
			if (_hidden.Remove(item))
			{
				Save();
				return false;
			}
			_favorites.Remove(item);
			_hidden.Add(item);
			Save();
			return true;
		}

		private static void Load()
		{
			try
			{
				if (!File.Exists(SavePath))
				{
					return;
				}
				SaveData saveData = JsonConvert.DeserializeObject<SaveData>(File.ReadAllText(SavePath));
				if (saveData == null)
				{
					return;
				}
				_favorites.Clear();
				_hidden.Clear();
				foreach (string item in saveData.Favorites ?? new List<string>())
				{
					_favorites.Add(item);
				}
				foreach (string item2 in saveData.Hidden ?? new List<string>())
				{
					_hidden.Add(item2);
				}
				Plugin.Logger.LogInfo((object)$"BridgeFavoritesManager: loaded {_favorites.Count} favorite(s), {_hidden.Count} hidden.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("BridgeFavoritesManager: load failed: " + ex.Message));
			}
		}

		private static void Save()
		{
			string json = JsonConvert.SerializeObject((object)new SaveData
			{
				Favorites = new List<string>(_favorites),
				Hidden = new List<string>(_hidden)
			}, (Formatting)1);
			_lastWrite = _lastWrite.ContinueWith(delegate
			{
				try
				{
					string text = SavePath + ".tmp";
					File.WriteAllText(text, json, Encoding.UTF8);
					if (File.Exists(SavePath))
					{
						File.Replace(text, SavePath, null);
					}
					else
					{
						File.Move(text, SavePath);
					}
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("BridgeFavoritesManager: save failed: " + ex.Message));
				}
			}, TaskScheduler.Default);
		}

		private static string KeyFor(CosmeticAsset asset)
		{
			if (!string.IsNullOrEmpty(asset.assetId))
			{
				return asset.assetId;
			}
			if (!string.IsNullOrEmpty(asset.assetName))
			{
				return asset.assetName;
			}
			return ((Object)asset).name ?? "";
		}
	}
	internal static class CosmeticOverridePopup
	{
		private const float PopupX = -120f;

		private const float TitleGap = 15f;

		private const float BtnRowH = 30f;

		private const float BtnTopGap = 10f;

		private const float BtnBackX = -137f;

		private const float BtnSaveX = 58f;

		private const float BtnResetX = 51f;

		private static readonly string[] RarityOptions = Enum.GetNames(typeof(Rarity));

		private static readonly string[] MainOptions = Enum.GetNames(typeof(MainCosmeticCategory));

		private static readonly string[] ModdedOptions = new string[3] { "Default", "Yes", "No" };

		private static readonly Dictionary<MainCosmeticCategory, OverrideCosmeticType[]> SubOptions = new Dictionary<MainCosmeticCategory, OverrideCosmeticType[]>
		{
			[MainCosmeticCategory.Head] = new OverrideCosmeticType[6]
			{
				OverrideCosmeticType.Hat,
				OverrideCosmeticType.Eyewear,
				OverrideCosmeticType.FaceTop,
				OverrideCosmeticType.FaceBottom,
				OverrideCosmeticType.HeadBottom,
				OverrideCosmeticType.Ears
			},
			[MainCosmeticCategory.Body] = new OverrideCosmeticType[2]
			{
				OverrideCosmeticType.BodyTop,
				OverrideCosmeticType.BodyBottom
			},
			[MainCosmeticCategory.Arms] = new OverrideCosmeticType[2]
			{
				OverrideCosmeticType.ArmRight,
				OverrideCosmeticType.ArmLeft
			},
			[MainCosmeticCategory.Legs] = new OverrideCosmeticType[4]
			{
				OverrideCosmeticType.LegRight,
				OverrideCosmeticType.LegLeft,
				OverrideCosmeticType.FootRight,
				OverrideCosmeticType.FootLeft
			},
			[MainCosmeticCategory.World] = new OverrideCosmeticType[1] { OverrideCosmeticType.World }
		};

		private static readonly Dictionary<OverrideCosmeticType, string> SubLabels = new Dictionary<OverrideCosmeticType, string>
		{
			[OverrideCosmeticType.Hat] = "Hat",
			[OverrideCosmeticType.Eyewear] = "Eyewear",
			[OverrideCosmeticType.FaceTop] = "Face Upper",
			[OverrideCosmeticType.FaceBottom] = "Face Middle",
			[OverrideCosmeticType.HeadBottom] = "Face Lower",
			[OverrideCosmeticType.Ears] = "Ears",
			[OverrideCosmeticType.BodyTop] = "Bodywear Top",
			[OverrideCosmeticType.BodyBottom] = "Bodywear Bottom",
			[OverrideCosmeticType.ArmRight] = "Armwear Right",
			[OverrideCosmeticType.ArmLeft] = "Armwear Left",
			[OverrideCosmeticType.LegRight] = "Legwear Right",
			[OverrideCosmeticType.LegLeft] = "Legwear Left",
			[OverrideCosmeticType.FootRight] = "Footwear Right",
			[OverrideCosmeticType.FootLeft] = "Footwear Left",
			[OverrideCosmeticType.World] = "World"
		};

		private static readonly Dictionary<string, OverrideCosmeticType> LabelToType = SubLabels.ToDictionary<KeyValuePair<OverrideCosmeticType, string>, string, OverrideCosmeticType>((KeyValuePair<OverrideCosmeticType, string> kvp) => kvp.Value, (KeyValuePair<OverrideCosmeticType, string> kvp) => kvp.Key);

		internal static void Show(CosmeticAsset asset)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Expected O, but got Unknown
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			CosmeticAsset asset2 = asset;
			bool flag = PerCosmeticOverrides.HasOverride(asset2);
			string text = asset2.assetName ?? ((Object)asset2).name ?? asset2.assetId;
			PerCosmeticOverrides.TryGet(asset2.assetId, out CosmeticOverrideData data);
			bool? pendingModded = data?.IsModded;
			Rarity pendingRarity = asset2.rarity;
			MainCosmeticCategory pendingMain = PerCosmeticOverrides.GetCurrentMain(asset2);
			OverrideCosmeticType pendingType = PerCosmeticOverrides.GetCurrentType(asset2);
			REPOPopupPage popup = MenuAPI.CreateREPOPopupPage(text, false, true, 5f, (Vector2?)new Vector2(-120f, 0f));
			REPOSlider subSlider = null;
			popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Expected O, but got Unknown
				REPOSlider val6 = MenuAPI.CreateREPOSlider("Main Category", "", (Action<string>)delegate(string opt)
				{
					if (Enum.TryParse<MainCosmeticCategory>(opt, out var result2) && result2 != pendingMain)
					{
						pendingMain = result2;
						pendingType = SubOptions[result2][0];
						if (!((Object)(object)subSlider == (Object)null))
						{
							REPOScrollViewElement component = ((Component)subSlider).GetComponent<REPOScrollViewElement>();
							if (result2 == MainCosmeticCategory.World)
							{
								if ((Object)(object)component != (Object)null)
								{
									component.visibility = false;
								}
							}
							else
							{
								subSlider.stringOptions = GetSubLabels(result2);
								subSlider.SetValue(0f, false);
								if ((Object)(object)component != (Object)null)
								{
									component.visibility = true;
								}
							}
						}
					}
				}, scrollView, MainOptions, pendingMain.ToString(), default(Vector2), "", "", (BarBehavior)0);
				return (RectTransform)((Component)val6).transform;
			}, 15f, 0f);
			popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Expected O, but got Unknown
				MainCosmeticCategory mainCosmeticCategory = ((pendingMain != MainCosmeticCategory.World) ? pendingMain : MainCosmeticCategory.Head);
				string[] subLabels = GetSubLabels(mainCosmeticCategory);
				string text3 = ((Array.IndexOf(SubOptions[mainCosmeticCategory], pendingType) >= 0 && SubLabels.ContainsKey(pendingType)) ? SubLabels[pendingType] : subLabels[0]);
				subSlider = MenuAPI.CreateREPOSlider("Sub Category", "", (Action<string>)delegate(string opt)
				{
					if (LabelToType.TryGetValue(opt, out var value))
					{
						pendingType = value;
					}
				}, scrollView, subLabels, text3, default(Vector2), "", "", (BarBehavior)0);
				return (RectTransform)((Component)subSlider).transform;
			}, 0f, 0f);
			if (pendingMain == MainCosmeticCategory.World)
			{
				REPOSlider obj = subSlider;
				REPOScrollViewElement val = ((obj != null) ? ((Component)obj).GetComponent<REPOScrollViewElement>() : null);
				if ((Object)(object)val != (Object)null)
				{
					val.visibility = false;
				}
			}
			popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0072: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Expected O, but got Unknown
				Action<string> action = delegate(string opt)
				{
					bool? flag2 = ((opt == "Yes") ? new bool?(true) : ((!(opt == "No")) ? null : new bool?(false)));
					pendingModded = flag2;
				};
				string text2 = ((!pendingModded.HasValue) ? "Default" : ((!pendingModded.GetValueOrDefault()) ? "No" : "Yes"));
				REPOSlider val5 = MenuAPI.CreateREPOSlider("Modded Rarity", "", action, scrollView, ModdedOptions, text2, default(Vector2), "", "", (BarBehavior)0);
				return (RectTransform)((Component)val5).transform;
			}, 0f, 0f);
			popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Expected O, but got Unknown
				REPOSlider val4 = MenuAPI.CreateREPOSlider("Rarity", "", (Action<string>)delegate(string opt)
				{
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					if (Enum.TryParse<Rarity>(opt, out Rarity result))
					{
						pendingRarity = result;
					}
				}, scrollView, RarityOptions, ((object)(Rarity)(ref pendingRarity)).ToString(), default(Vector2), "", "", (BarBehavior)0);
				return (RectTransform)((Component)val4).transform;
			}, 0f, 0f);
			popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
			{
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				RectTransform val3 = MakeRow(scrollView);
				MenuAPI.CreateREPOButton("Back", (Action)delegate
				{
					popup.ClosePage(false);
				}, (Transform)(object)val3, new Vector2(-137f, 0f));
				MenuAPI.CreateREPOButton("Save", (Action)delegate
				{
					//IL_000d: Unknown result type (might be due to invalid IL or missing references)
					PerCosmeticOverrides.SetAndApply(asset2, pendingModded, pendingRarity, pendingType);
					RefreshMenu();
					popup.ClosePage(false);
				}, (Transform)(object)val3, new Vector2(58f, 0f));
				return val3;
			}, 10f, 0f);
			if (flag)
			{
				popup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform scrollView)
				{
					//IL_0036: Unknown result type (might be due to invalid IL or missing references)
					RectTransform val2 = MakeRow(scrollView);
					MenuAPI.CreateREPOButton("Reset", (Action)delegate
					{
						PerCosmeticOverrides.Reset(asset2);
						RefreshMenu();
						popup.ClosePage(false);
					}, (Transform)(object)val2, new Vector2(51f, 0f));
					return val2;
				}, 5f, 0f);
			}
			popup.OpenPage(false);
		}

		private static string[] GetSubLabels(MainCosmeticCategory main)
		{
			return Array.ConvertAll(SubOptions[main], (OverrideCosmeticType t) => SubLabels[t]);
		}

		private static RectTransform MakeRow(Transform scrollView)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = new GameObject("Button Row", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(scrollView, false);
			component.sizeDelta = new Vector2(0f, 30f);
			return component;
		}

		private static void RefreshMenu()
		{
			MenuPageCosmetics? activePage = CosmeticsMenuState.ActivePage;
			if (activePage != null)
			{
				activePage.RefreshScrollContent();
			}
		}
	}
	internal static class CosmeticsMenuState
	{
		[CompilerGenerated]
		private sealed class <SearchRefreshCoroutine>d__51 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public MenuPageCosmetics page;

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

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

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

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

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(0.25f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					_searchDebounce = null;
					page.RefreshScrollContent();
					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();
			}
		}

		private static Coroutine? _searchDebounce;

		private const float SearchDebounceDelay = 0.25f;

		private static Dictionary<CosmeticAsset, int>? _assetIndexCache;

		internal static CosmeticCategoryAsset? SelectedCategory { get; private set; }

		internal static CosmeticCategoryAsset? SearchCategory { get; private set; }

		internal static CosmeticCategoryAsset? FavoritesCategory { get; private set; }

		internal static CosmeticCategoryAsset? HiddenCategory { get; private set; }

		internal static TextMeshProUGUI? StatusLabel { get; private set; }

		internal static TMP_InputField? SearchField { get; private set; }

		internal static GameObject? EmptyStateLabel { get; private set; }

		internal static bool SearchMode { get; private set; }

		internal static string SearchText { get; private set; } = "";


		internal static MenuPageCosmetics? ActivePage { get; private set; }

		internal static bool IsVirtual(CosmeticCategoryAsset? c)
		{
			if ((Object)(object)c != (Object)null)
			{
				if (!((Object)(object)c == (Object)(object)SelectedCategory) && !((Object)(object)c == (Object)(object)SearchCategory) && !((Object)(object)c == (Object)(object)FavoritesCategory))
				{
					return (Object)(object)c == (Object)(object)HiddenCategory;
				}
				return true;
			}
			return false;
		}

		internal static bool IsSelected(CosmeticCategoryAsset? c)
		{
			if ((Object)(object)c != (Object)null)
			{
				return (Object)(object)c == (Object)(object)SelectedCategory;
			}
			return false;
		}

		internal static bool IsSearch(CosmeticCategoryAsset? c)
		{
			if ((Object)(object)c != (Object)null)
			{
				return (Object)(object)c == (Object)(object)SearchCategory;
			}
			return false;
		}

		internal static bool IsFavCategory(CosmeticCategoryAsset? c)
		{
			if ((Object)(object)c != (Object)null)
			{
				return (Object)(object)c == (Object)(object)FavoritesCategory;
			}
			return false;
		}

		internal static bool IsHideCategory(CosmeticCategoryAsset? c)
		{
			if ((Object)(object)c != (Object)null)
			{
				return (Object)(object)c == (Object)(object)HiddenCategory;
			}
			return false;
		}

		internal static void EnsureCategories()
		{
			if (SelectedCategory == null)
			{
				SelectedCategory = MakeCategory("MHB_Selected", "SELECTED");
			}
			if (SearchCategory == null)
			{
				SearchCategory = MakeCategory("MHB_Search", "SEARCH");
			}
			if (FavoritesCategory == null)
			{
				FavoritesCategory = MakeCategory("MHB_Favorites", "FAV");
			}
			if (HiddenCategory == null)
			{
				HiddenCategory = MakeCategory("MHB_Hidden", "HIDE");
			}
		}

		internal static void SetStatusLabel(TextMeshProUGUI? v)
		{
			StatusLabel = v;
		}

		internal static void SetSearchField(TMP_InputField? v)
		{
			SearchField = v;
		}

		internal static void SetEmptyStateLabel(GameObject? v)
		{
			EmptyStateLabel = v;
		}

		internal static void SetSearchMode(bool v)
		{
			SearchMode = v;
		}

		internal static void SetSearchText(string v)
		{
			SearchText = v;
		}

		internal static void ClearSearch()
		{
			SearchText = "";
			SearchMode = false;
			if ((Object)(object)SearchField != (Object)null)
			{
				SearchField.SetTextWithoutNotify("");
			}
		}

		internal static void ScheduleSearchRefresh()
		{
			MenuPageCosmetics activePage = ActivePage;
			if (!((Object)(object)activePage == (Object)null))
			{
				if (_searchDebounce != null)
				{
					((MonoBehaviour)activePage).StopCoroutine(_searchDebounce);
				}
				_searchDebounce = ((MonoBehaviour)activePage).StartCoroutine(SearchRefreshCoroutine(activePage));
			}
		}

		[IteratorStateMachine(typeof(<SearchRefreshCoroutine>d__51))]
		private static IEnumerator SearchRefreshCoroutine(MenuPageCosmetics page)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SearchRefreshCoroutine>d__51(0)
			{
				page = page
			};
		}

		internal static void SetActivePage(MenuPageCosmetics? v)
		{
			ActivePage = v;
		}

		internal static void OnMenuClosed()
		{
			if (_searchDebounce != null && (Object)(object)ActivePage != (Object)null)
			{
				((MonoBehaviour)ActivePage).StopCoroutine(_searchDebounce);
			}
			_searchDebounce = null;
			ActivePage = null;
			_assetIndexCache = null;
		}

		internal static int GetAssetIndex(CosmeticAsset asset)
		{
			if ((Object)(object)MetaManager.instance == (Object)null)
			{
				return -1;
			}
			if (_assetIndexCache == null)
			{
				List<CosmeticAsset> cosmeticAssets = MetaManager.instance.cosmeticAssets;
				_assetIndexCache = new Dictionary<CosmeticAsset, int>(cosmeticAssets.Count);
				for (int i = 0; i < cosmeticAssets.Count; i++)
				{
					if ((Object)(object)cosmeticAssets[i] != (Object)null)
					{
						_assetIndexCache[cosmeticAssets[i]] = i;
					}
				}
			}
			if (!_assetIndexCache.TryGetValue(asset, out var value))
			{
				return -1;
			}
			return value;
		}

		internal static bool IsPresetsCategory(CosmeticCategoryAsset? cat)
		{
			if ((Object)(object)cat == (Object)null)
			{
				return false;
			}
			string text = (cat.categoryName ?? ((Object)cat).name ?? "").ToUpperInvariant();
			if (!text.Contains("PRESET"))
			{
				return text.Contains("OUTFIT");
			}
			return true;
		}

		private static CosmeticCategoryAsset MakeCategory(string id, string label)
		{
			CosmeticCategoryAsset val = ScriptableObject.CreateInstance<CosmeticCategoryAsset>();
			((Object)val).name = id;
			val.categoryName = label;
			val.typeList = Enum.GetValues(typeof(CosmeticType)).Cast<CosmeticType>().ToList();
			return val;
		}
	}
	internal static class FavHideMarkerHelper
	{
		private const string MarkerName = "MHB_FavHideMarker";

		private const float OffsetX = -7f;

		private const float OffsetY = 7f;

		private const float Size = 9f;

		internal static void UpdateMarker(MenuElementCosmeticButton btn)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)btn == (Object)null || (Object)(object)btn.cosmeticAsset == (Object)null)
			{
				return;
			}
			bool flag = BridgeFavoritesManager.IsFavorite(btn.cosmeticAsset);
			bool flag2 = BridgeFavoritesManager.IsHidden(btn.cosmeticAsset);
			Transform val = ((Component)btn).transform.Find("MHB_FavHideMarker");
			if (!flag && !flag2)
			{
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)val).gameObject);
				}
				return;
			}
			Image val4;
			if ((Object)(object)val == (Object)null)
			{
				GameObject val2 = new GameObject("MHB_FavHideMarker");
				RectTransform val3 = val2.AddComponent<RectTransform>();
				val2.transform.SetParent(((Component)btn).transform, false);
				val2.transform.SetAsLastSibling();
				val3.anchorMin = new Vector2(1f, 0f);
				val3.anchorMax = new Vector2(1f, 0f);
				val3.pivot = new Vector2(1f, 0f);
				ApplyRect(val3);
				val4 = val2.AddComponent<Image>();
				((Graphic)val4).raycastTarget = false;
				val4.preserveAspect = true;
			}
			else
			{
				val.SetAsLastSibling();
				ApplyRect(((Component)val).GetComponent<RectTransform>());
				val4 = ((Component)val).GetComponent<Image>();
			}
			if (!((Object)(object)val4 == (Object)null))
			{
				if (flag)
				{
					val4.sprite = FavHideIcons.StarSprite;
					((Graphic)val4).color = Color.white;
				}
				else
				{
					val4.sprite = FavHideIcons.HideSprite;
					((Graphic)val4).color = Color.white;
				}
			}
		}

		private static void ApplyRect(RectTransform? rt)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rt == (Object)null))
			{
				rt.anchoredPosition = new Vector2(-7f, 7f);
				rt.sizeDelta = new Vector2(9f, 9f);
			}
		}
	}
	[HarmonyPatch]
	internal static class CosmeticsBulkActionRefreshPatch
	{
		[CompilerGenerated]
		private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private MethodBase <>2__current;

			private int <>l__initialThreadId;

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

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

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

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

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "RandomizeAllButton", (Type[])null, (Type[])null);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "RandomizeCosmeticsButton", (Type[])null, (Type[])null);
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					<>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "ResetAllButton", (Type[])null, (Type[])null);
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					<>2__current = AccessTools.Method(typeof(MenuPageCosmetics), "ResetCosmeticsButton", (Type[])null, (Type[])null);
					<>1__state = 4;
					return true;
				case 4:
					<>1__state = -1;
					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<MethodBase> IEnumerable<MethodBase>.GetEnumerator()
			{
				if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
				{
					<>1__state = 0;
					return this;
				}
				return new <TargetMethods>d__0(0);
			}

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

		[IteratorStateMachine(typeof(<TargetMethods>d__0))]
		private static IEnumerable<MethodBase> TargetMethods()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <TargetMethods>d__0(-2);
		}

		[HarmonyPostfix]
		private static void Postfix(MenuPageCosmetics __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__instance.selectedTab == 0 && CosmeticsMenuState.IsSelected(__instance.selectedCategory))
			{
				__instance.RefreshScrollContent();
			}
		}
	}
	[HarmonyPatch(typeof(MenuPageCosmetics), "RefreshScrollContent")]
	internal static class CosmeticsFilterPatch
	{
		private const float SectionSpacing = 10f;

		private const float SectionHeader = 40f;

		internal const string WorldSectionName = "MHB_WorldSection";

		internal const CosmeticType WorldSubCategory = 999;

		[HarmonyPostfix]
		private static void Postfix(MenuPageCosmetics __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Invalid comparison between Unknown and I4
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Invalid comparison between Unknown and I4
			//IL_03f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Expected O, but got Unknown
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			//IL_048d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d9: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__instance.selectedTab == 1)
			{
				UpdateSearchFieldVisibility(isSearch: false);
				HideEmptyState();
				return;
			}
			CosmeticCategoryAsset selectedCategory = __instance.selectedCategory;
			if ((Object)(object)selectedCategory == (Object)null)
			{
				return;
			}
			if (CosmeticsMenuState.IsPresetsCategory(selectedCategory))
			{
				UpdateSearchFieldVisibility(isSearch: false);
				HideEmptyState();
				return;
			}
			bool flag = CosmeticsMenuState.IsSelected(selectedCategory);
			bool flag2 = CosmeticsMenuState.IsSearch(selectedCategory);
			bool flag3 = CosmeticsMenuState.IsFavCategory(selectedCategory);
			bool flag4 = CosmeticsMenuState.IsHideCategory(selectedCategory);
			bool flag5 = CosmeticsMenuState.IsVirtual(selectedCategory);
			string text = (CosmeticsMenuState.SearchText?.Trim() ?? "").ToLowerInvariant();
			bool flag6 = text.Length > 0;
			UpdateSearchFieldVisibility(flag2);
			BridgeFavoritesManager.EnsureLoaded();
			bool flag7 = !flag4 && !flag && BridgeFavoritesManager.HasAnyHidden();
			if (!flag5 && !flag6 && !flag7)
			{
				SortFavoritesInCategory(__instance);
				HideEmptyState();
			}
			else
			{
				if ((Object)(object)MetaManager.instance == (Object)null)
				{
					return;
				}
				HashSet<int> equippedSet = new HashSet<int>(MetaManager.instance.cosmeticEquipped);
				HashSet<int> unlocksSet = new HashSet<int>(MetaManager.instance.cosmeticUnlocks);
				Dictionary<CosmeticAsset, int> assetIndexMap = BuildAssetIndexMap(MetaManager.instance);
				Dictionary<CosmeticType, GameObject> dictionary = new Dictionary<CosmeticType, GameObject>();
				foreach (Transform item in __instance.subCategoriesTransform)
				{
					Transform val = item;
					MenuElementButtonCosmeticCategory component = ((Component)val).GetComponent<MenuElementButtonCosmeticCategory>();
					if ((Object)(object)component != (Object)null && (int)component.buttonType == 1)
					{
						dictionary[component.subCategory] = ((Component)val).gameObject;
					}
				}
				foreach (GameObject value in dictionary.Values)
				{
					value.SetActive(!flag5);
				}
				float num = 0f;
				int num2 = 0;
				bool flag8 = flag5 && HhhCosmeticLoader.WorldAssetIds.Count > 0;
				MenuElementCosmeticSection val2 = null;
				foreach (MenuElementCosmeticSection item2 in __instance.sections.ToList())
				{
					if (item2.isStickyHeader)
					{
						continue;
					}
					bool flag9 = flag8 && (int)item2.subCategory == 0;
					MenuElementCosmeticButton[] componentsInChildren = ((Component)item2.cosmeticListTransform).GetComponentsInChildren<MenuElementCosmeticButton>(true);
					MenuElementCosmeticButton[] array = componentsInChildren.Where((MenuElementCosmeticButton b) => (Object)(object)b != (Object)null && (Object)(object)b.cosmeticAsset != (Object)null).ToArray();
					int num3 = 0;
					MenuElementCosmeticButton[] array2 = array;
					foreach (MenuElementCosmeticButton val3 in array2)
					{
						if ((Object)(object)val3 == (Object)null || (Object)(object)((Component)val3).gameObject == (Object)null)
						{
							continue;
						}
						bool flag10;
						if (flag9 && HhhCosmeticLoader.IsWorldAsset(val3.cosmeticAsset))
						{
							flag10 = false;
						}
						else
						{
							if (!flag5 && flag7)
							{
								if (BridgeFavoritesManager.IsHidden(val3.cosmeticAsset) && ((Component)val3).gameObject.activeSelf)
								{
									((Component)val3).gameObject.SetActive(false);
								}
								if (((Component)val3).gameObject.activeSelf)
								{
									FavHideMarkerHelper.UpdateMarker(val3);
								}
								continue;
							}
							flag10 = Matches(val3.cosmeticAsset, flag, flag2, flag3, flag4, flag7, flag6, text, equippedSet, assetIndexMap, unlocksSet);
						}
						if (((Component)val3).gameObject.activeSelf != flag10)
						{
							((Component)val3).gameObject.SetActive(flag10);
						}
						if (flag10)
						{
							FavHideMarkerHelper.UpdateMarker(val3);
						}
						else
						{
							num3++;
						}
					}
					int num4 = array.Length - num3;
					if (num4 == 0)
					{
						if (flag5)
						{
							__instance.sections.Remove(item2);
							Object.Destroy((Object)(object)((Component)item2).gameObject);
						}
						continue;
					}
					num2 += num4;
					if (flag5)
					{
						if (!((Component)item2).gameObject.activeSelf)
						{
							((Component)item2).gameObject.SetActive(true);
						}
						if ((Object)(object)item2.highlightObj != (Object)null)
						{
							((Component)item2.highlightObj).gameObject.SetActive(false);
						}
						GridLayoutGroup component2 = ((Component)item2.cosmeticListTransform).GetComponent<GridLayoutGroup>();
						((LayoutGroup)component2).padding = new RectOffset(((LayoutGroup)component2).padding.left, ((LayoutGroup)component2).padding.right, ((LayoutGroup)component2).padding.top, 0);
						int num5 = Mathf.Max(1, component2.constraintCount);
						int num6 = Mathf.Max(1, Mathf.CeilToInt((float)(num4 + 1) / (float)num5));
						float num7 = component2.cellSize.y * (float)num6 + component2.spacing.y * (float)(num6 - 1) + (float)((LayoutGroup)component2).padding.top + (float)((LayoutGroup)component2).padding.bottom;
						float num8 = 40f + num7;
						RectTransform component3 = ((Component)item2).GetComponent<RectTransform>();
						((Transform)component3).localPosition = new Vector3(((Transform)component3).localPosition.x, num, ((Transform)component3).localPosition.z);
						component3.sizeDelta = new Vector2(component3.sizeDelta.x, num8);
						RectTransform component4 = ((Component)item2.cosmeticListTransform).GetComponent<RectTransform>();
						component4.sizeDelta = new Vector2(component4.sizeDelta.x, num7);
						LayoutRebuilder.ForceRebuildLayoutImmediate(component4);
						LayoutRebuilder.ForceRebuildLayoutImmediate(component3);
						val2 = item2;
						num -= num8 + 10f;
					}
				}
				if (!flag5 || flag2 || flag || flag3 || flag4)
				{
					SortFavoritesInCategory(__instance, flag);
				}
				int num9 = (flag8 ? InjectWorldSection(__instance, num, flag, flag2, flag3, flag4, flag7, flag6, text, equippedSet, assetIndexMap, unlocksSet) : 0);
				num2 += num9;
				if (flag5)
				{
					MenuElementCosmeticSection obj;
					if (num9 <= 0)
					{
						obj = val2;
					}
					else
					{
						List<MenuElementCosmeticSection> sections = __instance.sections;
						obj = sections[sections.Count - 1];
					}
					MenuElementCosmeticSection section = obj;
					ApplyStickyPadding(__instance, section);
				}
				if (flag5 && num2 == 0)
				{
					string message = (flag3 ? "Add a favorite with Ctrl+click :)" : (flag4 ? "Hide cosmetics with Alt+click :P" : ((!flag2) ? "Equip a cosmetic to see it here :3" : (string.IsNullOrWhiteSpace(CosmeticsMenuState.SearchText) ? "Type to search cosmetics here :)" : "No cosmetics found :'("))));
					ShowEmptyState(message);
				}
				else
				{
					HideEmptyState();
				}
				if (flag5)
				{
					RebuildScroll(__instance);
				}
			}
		}

		private static void SortFavoritesInCategory(MenuPageCosmetics page, bool hiddenAtEnd = false)
		{
			bool flag = BridgeFavoritesManager.HasAnyFavorite();
			bool hasHidden = hiddenAtEnd && BridgeFavoritesManager.HasAnyHidden();
			foreach (MenuElementCosmeticSection section in page.sections)
			{
				if ((Object)(object)section == (Object)null || (Object)(object)section.cosmeticListTransform == (Object)null)
				{
					continue;
				}
				MenuElementCosmeticButton[] componentsInChildren = ((Component)section.cosmeticListTransform).GetComponentsInChildren<MenuElementCosmeticButton>(true);
				MenuElementCosmeticButton[] array = componentsInChildren;
				foreach (MenuElementCosmeticButton val in array)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)val.cosmeticAsset != (Object)null && ((Component)val).gameObject.activeSelf)
					{
						FavHideMarkerHelper.UpdateMarker(val);
					}
				}
				MenuElementCosmeticButton val2 = ((IEnumerable<MenuElementCosmeticButton>)componentsInChildren).FirstOrDefault((Func<MenuElementCosmeticButton, bool>)((MenuElementCosmeticButton b) => (Object)(object)b != (Object)null && (Object)(object)b.cosmeticAsset == (Object)null));
				MenuElementCosmeticButton[] array2 = componentsInChildren.Where((MenuElementCosmeticButton b) => (Object)(object)b != (Object)null && (Object)(object)b.cosmeticAsset != (Object)null).ToArray();
				if (array2.Length == 0)
				{
					continue;
				}
				bool flag2 = flag && array2.Any((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf && BridgeFavoritesManager.IsFavorite(b.cosmeticAsset));
				bool flag3 = hasHidden && array2.Any((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf && BridgeFavoritesManager.IsHidden(b.cosmeticAsset));
				bool flag4 = array2.Any((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf && PerCosmeticOverrides.IsModdedForAsset(b.cosmeticAsset));
				if (!flag2 && !flag3 && !flag4)
				{
					continue;
				}
				MenuElementCosmeticButton[] array3 = array2.Where((MenuElementCosmeticButton b) => ((Component)b).gameObject.activeSelf).OrderBy(delegate(MenuElementCosmeticButton b)
				{
					if (BridgeFavoritesManager.IsFavorite(b.cosmeticAsset))
					{
						return 0;
					}
					return (!hasHidden || !BridgeFavoritesManager.IsHidden(b.cosmeticAsset)) ? 1 : 3;
				}).ThenBy((MenuElementCosmeticButton b) => (!IsUnlocked(b)) ? 1 : 0)
					.ThenBy((MenuElementCosmeticButton b) => (!PerCosmeticOverrides.IsModdedForAsset(b.cosmeticAsset)) ? 1 : 0)
					.ThenBy((MenuElementCosmeticButton b) => ((Component)b).transform.GetSiblingIndex())
					.ToArray();
				MenuElementCosmeticButton[] array4 = (from b in array2
					where !((Component)b).gameObject.activeSelf
					orderby ((Component)b).transform.GetSiblingIndex()
					select b).ToArray();
				int num = 0;
				if ((Object)(object)val2 != (Object)null)
				{
					((Component)val2).transform.SetSiblingIndex(num++);
				}
				MenuElementCosmeticButton[] array5 = array3;
				foreach (MenuElementCosmeticButton val3 in array5)
				{
					((Component)val3).transform.SetSiblingIndex(num++);
				}
				MenuElementCosmeticButton[] array6 = array4;
				foreach (MenuElementCosmeticButton val4 in array6)
				{
					((Component)val4).transform.SetSiblingIndex(num++);
				}
				Transform cosmeticListTransform = section.cosmeticListTransform;
				RectTransform val5 = ((cosmeticListTransform != null) ? ((Component)cosmeticListTransform).GetComponent<RectTransform>() : null);
				if ((Object)(object)val5 != (Object)null)
				{
					LayoutRebuilder.ForceRebuildLayoutImmediate(val5);
				}
			}
		}

		private static bool IsUnlocked(MenuElementCosmeticButton btn)
		{
			if ((Object)(object)MetaManager.instance == (Object)null)
			{
				return true;
			}
			int assetIndex = CosmeticsMenuState.GetAssetIndex(btn.cosmeticAsset);
			if (assetIndex < 0)
			{
				return true;
			}
			return MetaManager.instance.cosmeticUnlocks.Contains(assetIndex);
		}

		private static void ApplyStickyPadding(MenuPageCosmetics page, MenuElementCosmeticSection? section)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)section == (Object)null)
			{
				return;
			}
			RectTransform val = page.stickyHeader?.viewport;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			RectTransform component = ((Component)section).GetComponent<RectTransform>();
			Transform cosmeticListTransform = section.cosmeticListTransform;
			RectTransform val2 = ((cosmeticListTransform != null) ? ((Component)cosmeticListTransform).GetComponent<RectTransform>() : null);
			Transform cosmeticListTransform2 = section.cosmeticListTransform;
			GridLayoutGroup val3 = ((cosmeticListTransform2 != null) ? ((Component)cosmeticListTransform2).GetComponent<GridLayoutGroup>() : null);
			if (!((Object)(object)component == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null))
			{
				Rect rect = val.rect;
				float num = Mathf.Max(0f, ((Rect)(ref rect)).height - component.sizeDelta.y - 10f);
				if (!(num <= 0f))
				{
					((LayoutGroup)val3).padding = new RectOffset(((LayoutGroup)val3).padding.left, ((LayoutGroup)val3).padding.right, ((LayoutGroup)val3).padding.top, (int)num);
					val2.sizeDelta = new Vector2(val2.sizeDelta.x, val2.sizeDelta.y + num);
					component.sizeDelta = new Vector2(component.sizeDelta.x, component.sizeDelta.y + num);
					LayoutRebuilder.ForceRebuildLayoutImmediate(val2);
					LayoutRebuilder.ForceRebuildLayoutImmediate(component);
				}
			}
		}

		private static int InjectWorldSection(MenuPageCosmetics page, float yPos, bool isSelected, bool isSearch, bool isFav, bool isHide, bool suppressHidden, bool applySearch, string search, HashSet<int> equippedSet, Dictionary<CosmeticAsset, int> assetIndexMap, HashSet<int> unlocksSet)
		{
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			string search2 = search;
			HashSet<int> equippedSet2 = equippedSet;
			Dictionary<CosmeticAsset, int> assetIndexMap2 = assetIndexMap;
			HashSet<int> unlocksSet2 = unlocksSet;
			for (int num = page.sections.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)page.sections[num] != (Object)null && ((Object)((Component)page.sections[num]).gameObject).name == "MHB_WorldSection")
				{
					Object.Destroy((Object)(object)((Component)page.sections[num]).gameObject);
					page.sections.RemoveAt(num);
				}
			}
			int value;
			List<CosmeticAsset> list = (from a in MetaManager.instance.cosmeticAssets
				where (Object)(object)a != (Object)null && a.prefab.IsValid() && HhhCosmeticLoader.IsWorldAsset(a) && Matches(a, isSelected, isSearch, isFav, isHide, suppressHidden, applySearch, search2, equippedSet2, assetIndexMap2, unlocksSet2)
				orderby !unlocksSet2.Contains(assetIndexMap2.TryGetValue(a, out value) ? value : (-1)), a.rarity descending, a.assetName
				select a).ToList();
			if (isSearch || isSelected)
			{
				bool hiddenAtEnd = isSelected;
				list = (from t in list.Select((CosmeticAsset a, int i) => (a, i))
					orderby (!BridgeFavoritesManager.IsFavorite(t.a)) ? ((!hiddenAtEnd || !BridgeFavoritesManager.IsHidden(t.a)) ? 1 : 3) : 0, t.i
					select t.a).ToList();
			}
			if (list.Count == 0)
			{
				return 0;
			}
			GameObject val = Object.Instantiate<GameObject>(page.sectionPrefab, page.sectionRootTransform);
			((Object)val).name = "MHB_WorldSection";
			MenuElementCosmeticSection component = val.GetComponent<MenuElementCosmeticSection>();
			component.subCategory = (CosmeticType)999;
			if ((Object)(object)component.headerText != (Object)null)
			{
				((TMP_Text)component.headerText).text = "WORLD";
				((TMP_Text)component.headerText).ForceMeshUpdate(false, false);
			}
			if ((Object)(object)component.highlightObj != (Object)null)
			{
				((Component)component.highlightObj).gameObject.SetActive(false);
			}
			GridLayoutGroup component2 = ((Component)component.cosmeticListTransform).GetComponent<GridLayoutGroup>();
			foreach (CosmeticAsset item in list)
			{
				GameObject val2 = Object.Instantiate<GameObject>(page.sectionButtonPrefab, component.cosmeticListTransform);
				MenuElementCosmeticButton component3 = val2.GetComponent<MenuElementCosmeticButton>();
				component3.cosmeticAsset = item;
				FavHideMarkerHelper.UpdateMarker(component3);
			}
			int count = list.Count;
			int num2 = Mathf.Max(1, component2.constraintCount);
			int num3 = Mathf.Max(1, Mathf.CeilToInt((float)(count + 1) / (float)num2));
			float num4 = component2.cellSize.y * (float)num3 + component2.spacing.y * (float)(num3 - 1) + (float)((LayoutGroup)component2).padding.top + (float)((LayoutGroup)component2).padding.bottom;
			float num5 = 40f + num4;
			RectTransform component4 = val.GetComponent<RectTransform>();
			((Transform)component4).localPosition = new Vector3(((Transform)component4).localPosition.x, yPos, ((Transform)component4).localPosition.z);
			component4.sizeDelta = new Vector2(component4.sizeDelta.x, num5);
			RectTransform component5 = ((Component)component.cosmeticListTransform).GetComponent<RectTransform>();
			component5.sizeDelta = new Vector2(component5.sizeDelta.x, num4);
			LayoutRebuilder.ForceRebuildLayoutImmediate(component5);
			LayoutRebuilder.ForceRebuildLayoutImmediate(component4);
			page.sections.Add(component);
			return count;
		}

		private static void UpdateSearchFieldVisibility(bool isSearch)
		{
			TMP_InputField searchField = CosmeticsMenuState.SearchField;
			if ((Object)(object)searchField == (Object)null)
			{
				return;
			}
			if (isSearch)
			{
				CosmeticsMenuState.SetSearchMode(v: true);
				((Component)searchField).gameObject.SetActive(true);
				return;
			}
			if (CosmeticsMenuState.SearchMode)
			{
				CosmeticsMenuState.ClearSearch();
			}
			((Component)searchField).gameObject.SetActive(false);
		}

		private static bool Matches(CosmeticAsset asset, bool isSelected, bool isSearch, bool isFav, bool isHide, bool suppressHidden, bool applySearch, string search, HashSet<int> equippedSet, Dictionary<CosmeticAsset, int> assetIndexMap, HashSet<int> unlocksSet)
		{
			if (isSearch && !applySearch)
			{
				return false;
			}
			assetIndexMap.TryGetValue(asset, out var value);
			if (isHide)
			{
				return BridgeFavoritesManager.IsHidden(asset);
			}
			if (isFav)
			{
				return BridgeFavoritesManager.IsFavorite(asset);
			}
			if (suppressHidden && BridgeFavoritesManager.IsHidden(asset))
			{
				return false;
			}
			if (isSelected && !equippedSet.Contains(value))
			{
				return false;
			}
			if (isSearch && value >= 0 && !unlocksSet.Contains(value))
			{
				return false;
			}
			if (applySearch)
			{
				string text = (asset.assetName ?? ((Object)asset).name ?? "").ToLowerInvariant();
				if (!text.Contains(search))
				{
					return false;
				}
			}
			return true;
		}

		private static Dictionary<CosmeticAsset, int> BuildAssetIndexMap(MetaManager meta)
		{
			Dictionary<CosmeticAsset, int> dictionary = new Dictionary<CosmeticAsset, int>(meta.cosmeticAssets.Count);
			for (int i = 0; i < meta.cosmeticAssets.Count; i++)
			{
				CosmeticAsset val = meta.cosmeticAssets[i];
				if ((Object)(object)val != (Object)null)
				{
					dictionary[val] = i;
				}
			}
			return dictionary;
		}

		private static void ShowEmptyState(string message)
		{
			GameObject emptyStateLabel = CosmeticsMenuState.EmptyStateLabel;
			if (!((Object)(object)emptyStateLabel == (Object)null))
			{
				TextMeshProUGUI component = emptyStateLabel.GetComponent<TextMeshProUGUI>();
				if ((Object)(object)component != (Object)null)
				{
					((TMP_Text)component).text = message;
				}
				if (!emptyStateLabel.activeSelf)
				{
					emptyStateLabel.SetActive(true);
				}
			}
		}

		private static void HideEmptyState()
		{
			GameObject emptyStateLabel = CosmeticsMenuState.EmptyStateLabel;
			if ((Object)(object)emptyStateLabel != (Object)null && emptyStateLabel.activeSelf)
			{
				emptyStateLabel.SetActive(false);
			}
		}

		private static void RebuildScroll(MenuPageCosmetics page)
		{
			ScrollRect componentInChildren = ((Component)page).GetComponentInChildren<ScrollRect>(true);
			if ((Object)(object)((componentInChildren != null) ? componentInChildren.content : null) != (Object)null)
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(componentInChildren.content);
			}
		}
	}
	[HarmonyPatch(typeof(MenuPageCosmetics), "LateUpdate")]
	internal static class CosmeticsMenuLateUpdatePatch
	{
		private const string Hint = "Ctrl+click = Fav\nAlt+click = Hide";

		private const float HintDelay = 2f;

		private const float HintFade = 0.5f;

		private const float HintAlpha = 0.4f;

		private static readonly Color NormalColor = Color.white;

		private static float _noHoverTime;

		internal static void OnMenuClosed()
		{
			_noHoverTime = 0f;
		}

		[HarmonyPostfix]
		private static void Postfix(MenuPageCosmetics __instance)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI statusLabel = CosmeticsMenuState.StatusLabel;
			if ((Object)(object)statusLabel == (Object)null)
			{
				return;
			}
			if ((int)__instance.selectedTab != 0)
			{
				_noHoverTime = 0f;
				((Component)((TMP_Text)statusLabel).transform.parent).gameObject.SetActive(false);
				return;
			}
			((Component)((TMP_Text)statusLabel).transform.parent).gameObject.SetActive(true);
			MenuElementCosmeticButton hoveredCosmeticButton = __instance.hoveredCosmeticButton;
			bool flag = false;
			if ((Object)(object)hoveredCosmeticButton != (Object)null)
			{
				flag = (Object)(object)hoveredCosmeticButton.cosmeticAsset != (Object)null || IsLocked(hoveredCosmeticButton);
			}
			if (flag)
			{
				_noHoverTime = 0f;
				string text;
				if (IsLocked(hoveredCosmeticButton))
				{
					text = "Locked";
				}
				else
				{
					CosmeticAsset cosmeticAsset = hoveredCosmeticButton.cosmeticAsset;
					string text2 = cosmeticAsset?.assetName ?? ((cosmeticAsset != null) ? ((Object)cosmeticAsset).name : null) ?? "";
					BridgeFavoritesManager.EnsureLoaded();
					bool fl