Decompiled source of MoreHeadBridge v1.0.0

MoreHeadBridge.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using REPOLib;
using REPOLib.Modules;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Xuaun")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Registers MoreHead .hhh cosmetics into the vanilla REPO cosmetics system via REPOLib.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a791020af3b3c6b26cc77cb7230db084ccc414a5")]
[assembly: AssemblyProduct("MoreHeadBridge")]
[assembly: AssemblyTitle("MoreHeadBridge")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.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)
		{
			return !string.IsNullOrEmpty(assetId) && assetId.StartsWith("morehead-bridge:", StringComparison.Ordinal);
		}

		internal static bool IsBridgeAsset(CosmeticAsset? asset)
		{
			return (Object)(object)asset != (Object)null && IsBridgeAsset(asset.assetId);
		}
	}
	internal static class HhhCosmeticLoader
	{
		internal static readonly List<string> RegisteredAssetIds = new List<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
		};

		private static readonly HashSet<string> ValidTags;

		private static readonly HashSet<string> _usedPrefabIds;

		private static readonly HashSet<string> _usedInternalNames;

		public static void LoadAll()
		{
			string pluginPath = Paths.PluginPath;
			string[] array = Directory.GetFiles(pluginPath, "*.hhh", SearchOption.AllDirectories);
			string text = Plugin.SpecificFolders.Value ?? "";
			if (!string.IsNullOrWhiteSpace(text))
			{
				string[] allowed = (from s in text.Split(',')
					select s.Trim() into s
					where s.Length > 0
					select s).ToArray();
				int num = array.Length;
				array = array.Where((string f) => allowed.Any((string a) => f.IndexOf(a, StringComparison.OrdinalIgnoreCase) >= 0)).ToArray();
				LogInfo(string.Format("SpecificFolders filter active ({0}) — kept {1}/{2} files.", string.Join(", ", allowed), array.Length, num));
			}
			LogInfo($"Found {array.Length} .hhh file(s). Translating cosmetics from MoreHead to Vanilla REPO...");
			int num2 = 0;
			List<string> list = new List<string>();
			string[] array2 = array;
			foreach (string path in array2)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
				ParseFileName(fileNameWithoutExtension, out string _, out string tag);
				if (tag == "world")
				{
					list.Add(Path.GetFileName(path));
					Plugin.Logger.LogDebug((object)("Skipped (world tag): " + fileNameWithoutExtension));
				}
				else if (TryRegister(path))
				{
					num2++;
				}
			}
			if (list.Count > 0)
			{
				Plugin.Logger.LogWarning((object)$"Skipped {list.Count} 'world' cosmetic(s) — no vanilla equivalent (run with Debug log level to see names).");
			}
			int num3 = array.Length;
			int num4 = num3 - num2 - list.Count;
			LogInfo($"Done — {num2}/{num3} registered. " + $"{list.Count} world-tag skipped, {num4} other error(s).");
		}

		private static bool TryRegister(string path)
		{
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: 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;
			}
			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 + "'"));
			}
			if (!Object.op_Implicit((Object)(object)val2.GetComponent<Cosmetic>()))
			{
				Cosmetic 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;
			Cosmetics.RegisterCosmetic(val6);
			RegisteredAssetIds.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 ?? ""));
			}
		}

		static HhhCosmeticLoader()
		{
			HashSet<string> hashSet = new HashSet<string>();
			foreach (string key in TagToType.Keys)
			{
				hashSet.Add(key);
			}
			hashSet.Add("world");
			ValidTags = hashSet;
			_usedPrefabIds = new HashSet<string>();
			_usedInternalNames = new HashSet<string>();
		}
	}
	internal static class BatchIconGenerator
	{
		[CompilerGenerated]
		private sealed class <Run>d__2 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private List<int> <savedPreview>5__1;

			private List<CosmeticAsset> <work>5__2;

			private int <done>5__3;

			private int <failed>5__4;

			private int[] <savedColorsPreview>5__5;

			private List<CosmeticAsset>.Enumerator <>s__6;

			private CosmeticAsset <asset>5__7;

			private List<CosmeticAsset>.Enumerator <>s__8;

			private CosmeticAsset <asset>5__9;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 2) <= 3u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<savedPreview>5__1 = null;
				<work>5__2 = null;
				<savedColorsPreview>5__5 = null;
				<>s__6 = default(List<CosmeticAsset>.Enumerator);
				<asset>5__7 = null;
				<>s__8 = default(List<CosmeticAsset>.Enumerator);
				<asset>5__9 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Expected O, but got Unknown
				//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d7: Expected O, but got Unknown
				//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>2__current = (object)new WaitForSeconds(0.5f);
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						if ((Object)(object)MetaManager.instance == (Object)null)
						{
							return false;
						}
						_ranThisSession = true;
						<savedPreview>5__1 = MetaManager.instance.cosmeticEquippedPreview?.ToList() ?? new List<int>();
						<work>5__2 = new List<CosmeticAsset>();
						<>s__6 = MetaManager.instance.cosmeticAssets.GetEnumerator();
						try
						{
							while (<>s__6.MoveNext())
							{
								<asset>5__7 = <>s__6.Current;
								if (!((Object)(object)<asset>5__7 == (Object)null) && <asset>5__7.assetId != null && BridgeIds.IsBridgeAsset(<asset>5__7) && !IconCapture.HasCache(<asset>5__7))
								{
									<work>5__2.Add(<asset>5__7);
									<asset>5__7 = null;
								}
							}
						}
						finally
						{
							((IDisposable)<>s__6).Dispose();
						}
						<>s__6 = default(List<CosmeticAsset>.Enumerator);
						Plugin.Logger.LogInfo((object)$"GenerateAllIcons: {<work>5__2.Count} icon(s) to generate.");
						<done>5__3 = 0;
						<failed>5__4 = 0;
						<savedColorsPreview>5__5 = ((MetaManager.instance.colorsEquippedPreview != null) ? ((int[])MetaManager.instance.colorsEquippedPreview.Clone()) : null);
						<>s__8 = <work>5__2.GetEnumerator();
						<>1__state = -3;
						break;
					case 2:
						<>1__state = -3;
						<>2__current = null;
						<>1__state = 3;
						return true;
					case 3:
						<>1__state = -3;
						<>2__current = null;
						<>1__state = 4;
						return true;
					case 4:
						<>1__state = -3;
						<>2__current = (object)new WaitForEndOfFrame();
						<>1__state = 5;
						return true;
					case 5:
						<>1__state = -3;
						if (IconCapture.TryCapture(<asset>5__9, <asset>5__9.type))
						{
							<done>5__3++;
						}
						else
						{
							<failed>5__4++;
						}
						MetaManager.instance.CosmeticUnequip(<asset>5__9, true, false, false);
						if ((<done>5__3 + <failed>5__4) % 50 == 0)
						{
							Plugin.Logger.LogInfo((object)$"Batch progress: {<done>5__3 + <failed>5__4}/{<work>5__2.Count} ({<done>5__3} ok, {<failed>5__4} failed)");
						}
						<asset>5__9 = null;
						break;
					}
					if (<>s__8.MoveNext())
					{
						<asset>5__9 = <>s__8.Current;
						MetaManager.instance.cosmeticEquippedPreview = MetaManager.instance.cosmeticEquipped.ToList();
						MetaManager.instance.colorsEquippedPreview = (int[])MetaManager.instance.colorsEquipped.Clone();
						MetaManager.instance.CosmeticEquip(<asset>5__9, true, true);
						MetaManager.instance.CosmeticPreviewSet(true);
						MetaManager.instance.CosmeticPlayerUpdateLocal(false, false);
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					<>m__Finally1();
					<>s__8 = default(List<CosmeticAsset>.Enumerator);
					MetaManager.instance.cosmeticEquippedPreview = <savedPreview>5__1;
					if (<savedColorsPreview>5__5 != null)
					{
						MetaManager.instance.colorsEquippedPreview = <savedColorsPreview>5__5;
					}
					MetaManager.instance.CosmeticPreviewSet(false);
					MetaManager.instance.CosmeticPlayerUpdateLocal(false, false);
					Plugin.GenerateAllIcons.Value = false;
					((BaseUnityPlugin)Plugin.Instance).Config.Save();
					Plugin.Logger.LogInfo((object)$"GenerateAllIcons done — {<done>5__3} captured, {<failed>5__4} 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;
				((IDisposable)<>s__8).Dispose();
			}

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

		private static bool _ranThisSession;

		internal static void TryStart(MonoBehaviour host)
		{
			if (!_ranThisSession && Plugin.GenerateAllIcons.Value)
			{
				host.StartCoroutine(Run());
			}
		}

		[IteratorStateMachine(typeof(<Run>d__2))]
		private static IEnumerator Run()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Run>d__2(0);
		}
	}
	[HarmonyPatch(typeof(MenuPageCosmetics), "Start")]
	internal static class BatchIconGeneratorTrigger
	{
		[HarmonyPostfix]
		private static void Postfix(MenuPageCosmetics __instance)
		{
			BatchIconGenerator.TryStart((MonoBehaviour)(object)__instance);
		}
	}
	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;

		internal static string CacheDir => Path.Combine(Application.persistentDataPath, "MoreHeadBridge_Icons");

		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)(object)val.renderTextureInstance != (Object)null)
			{
				return val.renderTextureInstance;
			}
			RawImage component = ((Component)val).GetComponent<RawImage>();
			return (RenderTexture?)(((Object)(object)component != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
		}

		internal static bool TryCapture(CosmeticAsset asset)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got I4
			//IL_000d->IL000d: Incompatible stack types: O vs I4
			//IL_0007->IL000d: Incompatible stack types: I4 vs O
			//IL_0007->IL000d: Incompatible stack types: O vs I4
			object obj = asset;
			int num;
			if (asset != null)
			{
				obj = asset.type;
				num = (int)obj;
			}
			else
			{
				num = 0;
				obj = num;
				num = (int)obj;
			}
			return TryCapture((CosmeticAsset)(object)num, (CosmeticType)obj);
		}

		internal static bool TryCapture(CosmeticAsset asset, CosmeticType type)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: 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));
				asset.icon = null;
				RefreshVisibleButtons(asset);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogDebug((object)("[MoreHeadBridge] 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_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected I4, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_015e: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			switch ((int)type)
			{
			case 0:
			case 5:
			case 6:
			case 14:
			case 15:
			case 17:
			case 18:
			case 24:
			case 25:
			case 30:
			case 31:
			case 32:
				return new Rect(0.22f, 0.62f, 0.56f, 0.35f);
			case 7:
			case 8:
			case 16:
			case 20:
			case 21:
			case 23:
				return new Rect(0.18f, 0.34f, 0.64f, 0.36f);
			case 1:
			case 9:
			case 13:
			case 26:
				return new Rect(0.05f, 0.3f, 0.5f, 0.4f);
			case 2:
			case 10:
			case 27:
				return new Rect(0.45f, 0.3f, 0.5f, 0.4f);
			case 3:
			case 11:
			case 19:
			case 28:
				return new Rect(0.1f, 0f, 0.45f, 0.45f);
			case 4:
			case 12:
			case 22:
			case 29:
				return new Rect(0.45f, 0f, 0.45f, 0.45f);
			default:
				return new Rect(0f, 0f, 1f, 1f);
			}
		}

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

		private static Texture2D ResizeBilinear(Texture2D src, int w, int h)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0038: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: 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_000c: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (x >= 0 && y >= 0 && x < size && y < size)
			{
				pixels[y * size + x] = color;
			}
		}
	}
	internal static class ModdedRpcRetrigger
	{
		private static FieldInfo? _cosmeticEquippedField;

		internal static void TryApply(Harmony harmony)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("REPOLib.Objects.PlayerCosmeticsModded");
				if (type == null)
				{
					Plugin.Logger.LogDebug((object)"PlayerCosmeticsModded not found — multiplayer bridge sync fix skipped.");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "SetupCosmeticsModdedRPC", (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					_cosmeticEquippedField = AccessTools.Field(type, "cosmeticEquipped");
					if (!(_cosmeticEquippedField == null))
					{
						MethodInfo method = typeof(ModdedRpcRetrigger).GetMethod("Postfix", BindingFlags.Static | BindingFlags.NonPublic);
						harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						Plugin.Logger.LogDebug((object)"Multiplayer bridge sync fix applied.");
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Could not apply multiplayer bridge sync fix: " + ex.Message));
			}
		}

		private static void Postfix(MonoBehaviourPun __instance)
		{
			if ((Object)(object)__instance.photonView == (Object)null || __instance.photonView.IsMine || !(_cosmeticEquippedField?.GetValue(__instance) is List<string> list) || list.Count == 0)
			{
				return;
			}
			bool flag = false;
			foreach (string item in list)
			{
				if (BridgeIds.IsBridgeAsset(item))
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				PlayerCosmetics component = ((Component)__instance).GetComponent<PlayerCosmetics>();
				if (component != null)
				{
					component.SetupCosmeticsLogic(Array.Empty<int>(), false);
				}
			}
		}
	}
	internal static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Xuaun.MoreHeadBridge";

		public const string PLUGIN_NAME = "MoreHead Bridge";

		public const string PLUGIN_VERSION = "1.0.0";
	}
	internal static class PartShrinkerBridge
	{
		private static bool _initialized;

		private static bool _available;

		private static Type? _shrinkerType;

		private static Type? _hiddenType;

		private static FieldInfo? _partField;

		private static FieldInfo? _hideChildrenField;

		private static MethodInfo? _addMethod;

		private static MethodInfo? _removeMethod;

		private static void EnsureInit()
		{
			if (_initialized)
			{
				return;
			}
			_initialized = true;
			try
			{
				_shrinkerType = AccessTools.TypeByName("MoreHeadUtilities.PartShrinker");
				_hiddenType = AccessTools.TypeByName("MoreHeadUtilities.HiddenParts");
				if (_shrinkerType == null || _hiddenType == null)
				{
					Plugin.Logger.LogDebug((object)"MoreHeadUtilities not loaded — PartShrinker bridge inactive.");
					return;
				}
				_partField = AccessTools.Field(_shrinkerType, "partToHide");
				_hideChildrenField = AccessTools.Field(_shrinkerType, "hideChildren");
				_addMethod = AccessTools.Method(_hiddenType, "AddHiddenPart", (Type[])null, (Type[])null);
				_removeMethod = AccessTools.Method(_hiddenType, "RemoveHiddenPart", (Type[])null, (Type[])null);
				_available = _partField != null && _hideChildrenField != null && _addMethod != null && _removeMethod != null;
				if (_available)
				{
					Plugin.Logger.LogInfo((object)"PartShrinker bridge installed.");
				}
				else
				{
					Plugin.Logger.LogWarning((object)"PartShrinker types found but reflection failed — disabled.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("PartShrinker bridge init error: " + ex.Message));
			}
		}

		internal static void OnSpawn(GameObject cosmetic, PlayerAvatarVisuals avatar)
		{
			Apply(cosmetic, avatar, isAdd: true);
		}

		internal static void OnRemove(GameObject cosmetic, PlayerAvatarVisuals avatar)
		{
			Apply(cosmetic, avatar, isAdd: false);
		}

		private static void Apply(GameObject cosmetic, PlayerAvatarVisuals avatar, bool isAdd)
		{
			EnsureInit();
			if (!_available || (Object)(object)cosmetic == (Object)null || (Object)(object)avatar == (Object)null)
			{
				return;
			}
			Component[] componentsInChildren;
			try
			{
				componentsInChildren = cosmetic.GetComponentsInChildren(_shrinkerType, true);
			}
			catch
			{
				return;
			}
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return;
			}
			Component val = ((Component)avatar).GetComponent(_hiddenType);
			if ((Object)(object)val == (Object)null)
			{
				try
				{
					val = ((Component)avatar).gameObject.AddComponent(_hiddenType);
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogDebug((object)("Could not add HiddenParts: " + ex.Message));
					return;
				}
			}
			MethodInfo methodInfo = (isAdd ? _addMethod : _removeMethod);
			Component[] array = componentsInChildren;
			foreach (Component val2 in array)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				try
				{
					object value = _partField.GetValue(val2);
					bool flag = (bool)_hideChildrenField.GetValue(val2);
					methodInfo.Invoke(val, new object[3] { value, flag, true });
					if (isAdd)
					{
						MonoBehaviour val3 = (MonoBehaviour)(object)((val2 is MonoBehaviour) ? val2 : null);
						if (val3 != null)
						{
							((Behaviour)val3).enabled = false;
						}
					}
				}
				catch (Exception ex2)
				{
					Plugin.Logger.LogDebug((object)("PartShrinker " + (isAdd ? "Add" : "Remove") + " failed: " + ex2.Message));
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerCosmetics), "InstantiateCosmetic")]
	internal static class PartShrinkerBridge_SpawnPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerCosmetics __instance, CosmeticAsset _cosmeticAsset, GameObject __result)
		{
			if (!((Object)(object)__result == (Object)null) && BridgeIds.IsBridgeAsset(_cosmeticAsset) && !((Object)(object)__instance?.playerAvatarVisuals == (Object)null))
			{
				PartShrinkerBridge.OnSpawn(__result, __instance.playerAvatarVisuals);
			}
		}
	}
	[HarmonyPatch(typeof(Cosmetic), "Remove")]
	internal static class PartShrinkerBridge_RemovePatch
	{
		[HarmonyPrefix]
		private static void Prefix(Cosmetic __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && BridgeIds.IsBridgeAsset(__instance.cosmeticAsset) && !((Object)(object)__instance.playerCosmetics?.playerAvatarVisuals == (Object)null))
			{
				PartShrinkerBridge.OnRemove(((Component)__instance).gameObject, __instance.playerCosmetics.playerAvatarVisuals);
			}
		}
	}
	internal static class PartShrinkerSuppressor
	{
		internal static void TryApply(Harmony harmony)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("MoreHeadUtilities.PartShrinker");
				if (type == null)
				{
					Plugin.Logger.LogDebug((object)"MoreHeadUtilities not loaded — PartShrinker suppressor skipped.");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "OnDisable", (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					MethodInfo method = typeof(PartShrinkerSuppressor).GetMethod("Finalizer", BindingFlags.Static | BindingFlags.NonPublic);
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null);
					Plugin.Logger.LogDebug((object)"PartShrinker.OnDisable NPE suppressor installed.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogWarning((object)("Could not install PartShrinker suppressor: " + ex.Message));
			}
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			if (__exception is NullReferenceException)
			{
				return null;
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(PlayerCosmetics), "InstantiateCosmetic")]
	internal static class ArmRotationPatch
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerCosmetics __instance, CosmeticAsset _cosmeticAsset, GameObject __result)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_00d5: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__result == (Object)null || !BridgeIds.IsBridgeAsset(_cosmeticAsset) || (Object)(object)__instance == (Object)null || (Object)(object)__instance.playerAvatarVisuals == (Object)null)
			{
				return;
			}
			string name;
			if ((int)_cosmeticAsset.type == 1)
			{
				name = "ANIM ARM R SCALE";
			}
			else
			{
				if ((int)_cosmeticAsset.type != 2)
				{
					return;
				}
				name = "code_arm_l";
			}
			Transform val = FindByName(((Component)__instance.playerAvatarVisuals).transform, name);
			PrefabRef prefab = _cosmeticAsset.prefab;
			GameObject val2 = ((prefab != null) ? prefab.Prefab : null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
			{
				__result.transform.SetParent(val, false);
				__result.transform.localPosition = val2.transform.localPosition;
				__result.transform.localRotation = val2.transform.localRotation;
				__result.transform.localScale = val2.transform.localScale;
			}
		}

		private static Transform? FindByName(Transform root, string name)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			if (((Object)root).name == name)
			{
				return root;
			}
			foreach (Transform item in root)
			{
				Transform root2 = item;
				Transform val = FindByName(root2, name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(MenuElementCosmeticButton), "Update")]
	internal static class CosmeticHoverPatch
	{
		[CompilerGenerated]
		private sealed class <CaptureAfterDelay>d__2 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public CosmeticAsset asset;

			private bool <ok>5__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 2;
					return true;
				case 2:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 3;
					return true;
				case 3:
					<>1__state = -1;
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 4;
					return true;
				case 4:
					<>1__state = -1;
					<ok>5__1 = IconCapture.TryCapture(asset);
					if (!<ok>5__1)
					{
						_scheduled.Remove(asset.assetId);
					}
					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 readonly HashSet<string> _scheduled = new HashSet<string>();

		[HarmonyPostfix]
		private static void Postfix(MenuElementCosmeticButton __instance)
		{
			if (Plugin.AutoCaptureIcons.Value)
			{
				CosmeticAsset cosmeticAsset = __instance.cosmeticAsset;
				if (!((Object)(object)cosmeticAsset == (Object)null) && BridgeIds.IsBridgeAsset(cosmeticAsset) && __instance.wasHovering && !IconCapture.HasCache(cosmeticAsset) && _scheduled.Add(cosmeticAsset.assetId))
				{
					((MonoBehaviour)__instance).StartCoroutine(CaptureAfterDelay(cosmeticAsset));
				}
			}
		}

		[IteratorStateMachine(typeof(<CaptureAfterDelay>d__2))]
		private static IEnumerator CaptureAfterDelay(CosmeticAsset asset)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CaptureAfterDelay>d__2(0)
			{
				asset = asset
			};
		}
	}
	[HarmonyPatch(typeof(Cosmetic), "Setup")]
	internal static class CosmeticSetupPatch
	{
		[HarmonyPrefix]
		private static void Prefix(Cosmetic __instance)
		{
			//IL_0023: 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_0031: Invalid comparison between Unknown and I4
			if (!((Object)(object)__instance == (Object)null) && BridgeIds.IsBridgeAsset(__instance.cosmeticAsset) && ((int)__instance.type == 0 || (int)__instance.type == 5) && (Object)(object)((Component)__instance).GetComponentInChildren<CosmeticPlayerCrown>(true) == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<CosmeticPlayerCrown>();
			}
		}
	}
	[HarmonyPatch(typeof(Cosmetic), "CustomTypesLogic")]
	internal static class CosmeticUpdatePatch
	{
		[HarmonyFinalizer]
		private static Exception? Finalizer(Cosmetic __instance, Exception? __exception)
		{
			if (!(__exception is NullReferenceException))
			{
				return __exception;
			}
			if (!BridgeIds.IsBridgeAsset(__instance?.cosmeticAsset))
			{
				return __exception;
			}
			return Plugin.ShowBridgeDebugLogs.Value ? __exception : null;
		}
	}
	[HarmonyPatch(typeof(MetaManager), "GetCosmeticsToUnequip")]
	internal static class GetCosmeticsToUnequipPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(MetaManager __instance, List<int> _cosmeticEquipped, CosmeticAsset _cosmeticAssetNew, ref List<CosmeticAsset> __result)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			__result = new List<CosmeticAsset>();
			if (!Object.op_Implicit((Object)(object)_cosmeticAssetNew))
			{
				return false;
			}
			CosmeticTypeAsset typeAsset = GetTypeAsset(__instance, _cosmeticAssetNew.type);
			foreach (int item in _cosmeticEquipped)
			{
				if (item < 0 || item >= __instance.cosmeticAssets.Count)
				{
					continue;
				}
				CosmeticAsset val = __instance.cosmeticAssets[item];
				if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val == (Object)(object)_cosmeticAssetNew)
				{
					continue;
				}
				CosmeticTypeAsset typeAsset2 = GetTypeAsset(__instance, val.type);
				bool flag = val.type == _cosmeticAssetNew.type && !(typeAsset?.canEquipMultiple ?? false);
				bool flag2 = ContainsType(typeAsset?.disabledTypeList, typeAsset2) || ContainsType(typeAsset2?.disabledTypeList, typeAsset);
				if (flag || flag2)
				{
					__result.Add(val);
					continue;
				}
				foreach (Type item2 in typeAsset?.disabledCustomTypeList ?? new List<Type>())
				{
					if (ContainsCustomType(val.customTypeList, item2) || ContainsCustomType(typeAsset2?.customTypeList, item2))
					{
						__result.Add(val);
						break;
					}
				}
			}
			return false;
		}

		private static CosmeticTypeAsset? GetTypeAsset(MetaManager metaManager, CosmeticType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Expected I4, but got Unknown
			int num = (int)type;
			if (num < 0 || num >= metaManager.cosmeticTypeAssets.Count)
			{
				return null;
			}
			return metaManager.cosmeticTypeAssets[num];
		}

		private static bool ContainsType(List<CosmeticType>? list, CosmeticTypeAsset? asset)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			return list != null && (Object)(object)asset != (Object)null && list.Contains(asset.type);
		}

		private static bool ContainsCustomType(List<Type>? list, Type value)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return list?.Contains(value) ?? false;
		}
	}
	[HarmonyPatch(typeof(CosmeticAsset), "GetIcon")]
	internal static class GetIconPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(CosmeticAsset __instance, ref Sprite? __result)
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance.icon != (Object)null)
			{
				__result = __instance.icon;
				return false;
			}
			PrefabRef prefab = __instance.prefab;
			if ((Object)(object)((prefab != null) ? prefab.Prefab : null) == (Object)null)
			{
				return true;
			}
			if ((Object)(object)__instance.prefab.Prefab.GetComponentInChildren<SemiIconMaker>(true) != (Object)null)
			{
				return true;
			}
			string text = IconCapture.CachePathFor(__instance);
			if (File.Exists(text))
			{
				__result = SemiFunc.LoadSpriteFromFile(text);
				__instance.icon = __result;
				return false;
			}
			if (BridgeIds.IsBridgeAsset(__instance))
			{
				if (Plugin.UseTextureAsPlaceholder.Value && HhhCosmeticLoader.BridgeIconTextures.TryGetValue(__instance.assetId, out Texture2D value) && (Object)(object)value != (Object)null)
				{
					__result = Sprite.Create(value, new Rect(0f, 0f, (float)((Texture)value).width, (float)((Texture)value).height), new Vector2(0.5f, 0.5f), 100f);
					((Object)__result).name = "BridgeIcon_" + ((Object)__instance).name;
				}
				else
				{
					__result = PlaceholderIcon.Get();
				}
				__instance.icon = __result;
			}
			else
			{
				__result = null;
			}
			return false;
		}
	}
	internal static class HideMoreHeadUIPatch
	{
		internal static bool SkipInitialize()
		{
			return false;
		}
	}
	[HarmonyPatch(typeof(MenuElementCosmeticButton), "UpdateIcon")]
	internal static class MenuIconNpeGuardPatch
	{
		[HarmonyFinalizer]
		private static Exception? Finalizer(MenuElementCosmeticButton __instance, Exception? __exception)
		{
			if (!(__exception is NullReferenceException))
			{
				return __exception;
			}
			if (!BridgeIds.IsBridgeAsset(__instance?.cosmeticAsset))
			{
				return __exception;
			}
			return Plugin.ShowBridgeDebugLogs.Value ? __exception : null;
		}
	}
	[HarmonyPatch(typeof(MetaManager), "Load")]
	internal static class UnlockPatch
	{
		private static readonly bool _resetRequestedAtStartup = Plugin.ResetUnlocks.Value;

		private static bool _resetDone;

		[HarmonyPostfix]
		private static void Postfix(MetaManager __instance)
		{
			if (_resetRequestedAtStartup && !_resetDone)
			{
				TryReset(__instance);
				BundleLoader.OnAllBundlesLoaded += OnBundlesLoaded;
			}
			else if (!Plugin.UnlockAll.Value)
			{
				Plugin.Logger.LogDebug((object)"UnlockAll=false, skipping auto-unlock.");
			}
			else
			{
				TryUnlock(__instance);
				BundleLoader.OnAllBundlesLoaded += OnBundlesLoaded;
			}
		}

		private static void OnBundlesLoaded()
		{
			BundleLoader.OnAllBundlesLoaded -= OnBundlesLoaded;
			if ((Object)(object)MetaManager.instance == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"MetaManager.instance is null in deferred path — skipping.");
				return;
			}
			if (_resetRequestedAtStartup && !_resetDone)
			{
				TryReset(MetaManager.instance);
				if (!_resetDone)
				{
					return;
				}
			}
			if (Plugin.UnlockAll.Value)
			{
				TryUnlock(MetaManager.instance);
			}
		}

		private static void TryUnlock(MetaManager instance)
		{
			int num = 0;
			foreach (string assetId in HhhCosmeticLoader.RegisteredAssetIds)
			{
				int num2 = instance.cosmeticAssets.FindIndex((CosmeticAsset a) => (Object)(object)a != (Object)null && a.assetId == assetId);
				if (num2 >= 0 && !instance.cosmeticUnlocks.Contains(num2))
				{
					instance.cosmeticUnlocks.Add(num2);
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Logger.LogInfo((object)$"Auto-unlocked {num} bridge cosmetic(s) (UnlockAll=true).");
			}
		}

		private static void TryReset(MetaManager instance)
		{
			HashSet<string> hashSet = new HashSet<string>(HhhCosmeticLoader.RegisteredAssetIds);
			if (hashSet.Count == 0)
			{
				return;
			}
			HashSet<int> hashSet2 = new HashSet<int>();
			for (int i = 0; i < instance.cosmeticAssets.Count; i++)
			{
				CosmeticAsset val = instance.cosmeticAssets[i];
				if ((Object)(object)val != (Object)null && hashSet.Contains(val.assetId))
				{
					hashSet2.Add(i);
				}
			}
			if (hashSet2.Count == 0)
			{
				Plugin.Logger.LogDebug((object)"ResetUnlocks: no bridge cosmetics in cosmeticAssets yet, deferring.");
				return;
			}
			int num = instance.cosmeticUnlocks.RemoveAll(hashSet2.Contains);
			int num2 = instance.cosmeticEquipped.RemoveAll(hashSet2.Contains);
			int num3 = instance.cosmeticHistory.RemoveAll(hashSet2.Contains);
			instance.Save(true);
			Plugin.ResetUnlocks.Value = false;
			((BaseUnityPlugin)Plugin.Instance).Config.Save();
			_resetDone = true;
			Plugin.Logger.LogInfo((object)($"ResetUnlocks: cleared {num} unlock(s), " + $"{num2} equipped, {num3} history entry. Flag reset to false."));
		}
	}
	[BepInPlugin("Xuaun.MoreHeadBridge", "MoreHead Bridge", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = new Harmony("Xuaun.MoreHeadBridge");

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Logger { get; private set; }

		public static ConfigEntry<bool> UnlockAll { get; private set; }

		public static ConfigEntry<bool> ResetUnlocks { get; private set; }

		public static ConfigEntry<bool> UseTextureAsPlaceholder { get; private set; }

		public static ConfigEntry<bool> AutoCaptureIcons { get; private set; }

		public static ConfigEntry<bool> GenerateAllIcons { get; private set; }

		public static ConfigEntry<bool> DeleteIconCache { get; private set; }

		public static ConfigEntry<string> DeleteIconsMatching { get; private set; }

		public static ConfigEntry<bool> HideMoreHeadButton { get; private set; }

		public static ConfigEntry<Rarity> DefaultRarity { get; private set; }

		public static ConfigEntry<string> SpecificFolders { get; private set; }

		public static ConfigEntry<bool> ShowBridgeDebugLogs { get; private set; }

		private void Awake()
		{
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			UnlockAll = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UnlockAll", true, "Auto-unlock NEW bridge cosmetics on every load.\n\nWhen TRUE  — every bridge cosmetic gets added to your inventory\n             on game start, so you never have to grind for them.\nWhen FALSE — bridge cosmetics behave like vanilla ones:\n             you have to earn them in-game.\n\nIMPORTANT: this flag only controls what happens going FORWARD.\nCosmetics unlocked while UnlockAll was TRUE get saved permanently to\nthe REPOLib modded save file. Flipping this to FALSE later does NOT\nremove them — REPOLib re-reads the save on every launch.\nIf you want to wipe existing unlocks, see the [Reset] section below.");
			HideMoreHeadButton = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HideMoreHeadButton", false, "If true, removes the MoreHead button from all menus so you can use only the vanilla cosmetics UI. Requires restart.");
			DefaultRarity = ((BaseUnityPlugin)this).Config.Bind<Rarity>("General", "DefaultRarity", (Rarity)0, "Rarity tier assigned to bridge cosmetics in the vanilla shop. Values: Common, Uncommon, Rare, UltraRare.");
			SpecificFolders = ((BaseUnityPlugin)this).Config.Bind<string>("General", "SpecificFolders", "", "Comma-separated subfolder names under BepInEx/plugins to scan for .hhh files. Empty = scan all. Example: 'Some-MoreHeadPack,Another-CosmeticsPack'. Matching is case-insensitive and uses path contains.");
			UseTextureAsPlaceholder = ((BaseUnityPlugin)this).Config.Bind<bool>("Icons", "UseTextureAsPlaceholder", true, "When TRUE (default) — the cosmetic's texture is used as the icon, overlaid on the placeholder background.\nWhen FALSE — the texture is NOT applied to the placeholder; the slot keeps the plain placeholder icon\n             until a captured icon (AutoCaptureIcons / GenerateAllIcons) replaces it.");
			AutoCaptureIcons = ((BaseUnityPlugin)this).Config.Bind<bool>("Icons", "AutoCaptureIcons", true, "Reactively capture icons while you browse the cosmetics menu.\n\nWhen TRUE  — every time you HOVER a bridge cosmetic in the menu,\n             the game's existing avatar preview is snapshotted and\n             saved as a PNG icon for that cosmetic. Next time the UI\n             asks for that icon it loads the PNG (instant).\n             Icons fill in gradually as you explore the menu.\nWhen FALSE — no captures. Bridge cosmetics keep the texture/placeholder\n             fallback icons.\n\nPNG cache lives in:\n  %userprofile%\\AppData\\LocalLow\\semiwork\\REPO\\MoreHeadBridge_Icons\\\nDelete that folder to wipe all generated icons.\n(We store icons OUTSIDE the vanilla cosmetics cache because REPOLib\n wipes that one on every launch for any non-vanilla cosmetic.)");
			GenerateAllIcons = ((BaseUnityPlugin)this).Config.Bind<bool>("Icons", "GenerateAllIcons", false, "ONE-SHOT trigger. When TRUE, the next time you open the cosmetics menu\nthe mod will cycle through EVERY bridge cosmetic without a cached icon,\npreview-equipping each one, snapshotting the avatar, and saving the PNG.\n\nEffects while running:\n  * The avatar will visibly rotate through cosmetics — that IS the progress.\n  * Console logs progress every 50 items.\n  * Expect ~1-3 minutes for 1600+ cosmetics.\n  * Whatever you had previewing/equipped is restored at the end.\n  * This flag auto-resets to FALSE so it doesn't fire again.\n\nUse this if you want all icons generated in one go instead of as you browse.\nRequires AutoCaptureIcons logic — keeps working even if AutoCaptureIcons=false.");
			DeleteIconCache = ((BaseUnityPlugin)this).Config.Bind<bool>("Icons", "DeleteIconCache", false, "ONE-SHOT trigger. When TRUE on launch, delete cached bridge icon PNGs from:\n  %userprofile%\\AppData\\LocalLow\\semiwork\\REPO\\MoreHeadBridge_Icons\\\nUse DeleteIconsMatching to filter which ones to delete.\nAuto-resets to FALSE after running.");
			DeleteIconsMatching = ((BaseUnityPlugin)this).Config.Bind<string>("Icons", "DeleteIconsMatching", "", "Optional comma-separated filter for DeleteIconCache. Case-insensitive\nsubstring match against the icon filename (which is the cosmetic's internal name).\nEmpty = delete ALL bridge icons.\nExample: 'PirateHat,Waluigi' deletes only icons whose name contains either.");
			ResetUnlocks = ((BaseUnityPlugin)this).Config.Bind<bool>("Reset", "ResetUnlocks", false, "⚠ DESTRUCTIVE ONE-SHOT TRIGGER ⚠\n\nSetting this to TRUE causes the NEXT game launch to:\n  1. Remove EVERY bridge cosmetic from your unlocks list\n  2. Remove them from any saved outfit/preset you have equipped\n  3. Remove them from your history\n  4. Rewrite the REPOLib modded save file\n  5. Auto-flip this flag back to FALSE so it doesn't fire again\n\nUse this if you want to start over with bridge cosmetics.\nIf UnlockAll=true, cosmetics are wiped and immediately re-unlocked on the same launch.\nSet UnlockAll=false FIRST if you want to keep them locked after the reset.\n\nThis does NOT touch vanilla cosmetics or cosmetics from other mods.\nThis does NOT delete the .hhh files — only the unlock state.");
			ShowBridgeDebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowBridgeDebugLogs", false, "If true, do NOT suppress NullReferenceExceptions for bridge cosmetics.\nUse this to diagnose bridge-only issues (will spam logs if the base game is noisy).");
			PrintBanner();
			HhhCosmeticLoader.LoadAll();
			IconCacheCleaner.Run();
			_harmony.PatchAll();
			if (HideMoreHeadButton.Value)
			{
				TryHideMoreHeadUI();
			}
			PartShrinkerSuppressor.TryApply(_harmony);
			ModdedRpcRetrigger.TryApply(_harmony);
		}

		private void TryHideMoreHeadUI()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("MoreHead.MoreHeadUI");
				if (type == null)
				{
					Logger.LogDebug((object)"HideMoreHeadButton=true but MoreHead is not loaded — skipping.");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "Initialize", (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					MethodInfo method = typeof(HideMoreHeadUIPatch).GetMethod("SkipInitialize", BindingFlags.Static | BindingFlags.NonPublic);
					_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Logger.LogInfo((object)"MoreHead UI hidden (HideMoreHeadButton=true).");
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Could not hide MoreHead UI: " + ex.Message));
			}
		}

		private static void PrintBanner()
		{
			if (BceConsole.IsAvailable)
			{
				BceConsole.WriteLine("══════════════════════════════════════════════════════════════════════════════════", ConsoleColor.DarkCyan);
				BceConsole.Write("[Info   :  MoreHead Bridge] ", ConsoleColor.Cyan);
				BceConsole.WriteLine("► MoreHead Bridge v1.0.0 by Xuaun", ConsoleColor.DarkCyan);
				BceConsole.Write("[Info   :  MoreHead Bridge] ", ConsoleColor.Cyan);
				BceConsole.WriteLine("  Translating .hhh cosmetics into vanilla REPO", ConsoleColor.DarkCyan);
				BceConsole.WriteLine("══════════════════════════════════════════════════════════════════════════════════", ConsoleColor.DarkCyan);
			}
			else
			{
				Logger.LogInfo((object)"MoreHead Bridge v1.0.0 by Xuaun");
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}