Decompiled source of BobasHats v1.1.4

BobaHats.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 BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using Zorro.Core;
using Zorro.Core.Serizalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BobaHats")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+13bde32de102c984b19d0f35157b9132f071e3c0")]
[assembly: AssemblyProduct("BobaHats")]
[assembly: AssemblyTitle("BobaHats")]
[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 BobaHats
{
	internal static class BobaHatsPatches
	{
		private const int Spacer1 = -1535012113;

		private const int Spacer2 = 1512782925;

		private static ManualLogSource Logger => Plugin.Instance.Logger;

		[HarmonyPatch(typeof(SyncPersistentPlayerDataPackage), "SerializeData")]
		[HarmonyPostfix]
		public static void SyncPersistentPlayerDataPackageSerializeData(SyncPersistentPlayerDataPackage __instance, BinarySerializer binarySerializer)
		{
			binarySerializer.WriteInt(0);
			binarySerializer.WriteInt(-1535012113);
			binarySerializer.WriteInt(1512782925);
			PersistentPlayerDataService service = GameHandler.GetService<PersistentPlayerDataService>();
			if (service == null)
			{
				Logger.LogError((object)"PersistentPlayerDataService is null, cannot set hat.");
				return;
			}
			int actorNumber = __instance.ActorNumber;
			PersistentPlayerData playerData = service.GetPlayerData(actorNumber);
			Player val = default(Player);
			if (playerData == null && PhotonNetwork.TryGetPlayer(actorNumber, ref val))
			{
				playerData = service.GetPlayerData(val);
			}
			if (playerData == null)
			{
				Logger.LogError((object)$"Player data for actor number {actorNumber} is null, cannot set hat.");
				return;
			}
			Customization customizationSingleton = Plugin.GetCustomizationSingleton();
			if ((Object)(object)customizationSingleton == (Object)null)
			{
				Logger.LogError((object)"Customization component not instantiated yet!");
				return;
			}
			CustomizationOption[] hats = customizationSingleton.hats;
			if (hats == null)
			{
				Logger.LogError((object)"No hats found in character customization, cannot set hat.");
				return;
			}
			int currentHat = playerData.customizationData.currentHat;
			if (currentHat < 0 || currentHat >= hats.Length)
			{
				Logger.LogWarning((object)$"Invalid hat index {currentHat} for player #{actorNumber}, custom hats may not be loaded yet!");
				Plugin.BroadcastPluginEvent("OnLoadHats");
			}
			hats = customizationSingleton.hats;
			if (currentHat < 0 || currentHat >= hats.Length)
			{
				Logger.LogError((object)$"Invalid hat index {currentHat} for player #{actorNumber}, custom hat may be missing!");
				return;
			}
			CustomizationOption obj = hats[currentHat];
			string text = ((obj != null) ? ((Object)obj).name : null) ?? "";
			string text2 = JsonConvert.SerializeObject((object)new
			{
				hat = text
			}, (Formatting)0);
			binarySerializer.WriteString(text2, Encoding.UTF8);
			Logger.LogDebug((object)$"Serialized hat for player #{actorNumber}: '{text}'");
		}

		[HarmonyPatch(typeof(SyncPersistentPlayerDataPackage), "DeserializeData")]
		[HarmonyPostfix]
		public static void SyncPersistentPlayerDataPackageDeserializeData(SyncPersistentPlayerDataPackage __instance, BinaryDeserializer binaryDeserializer)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			if (binaryDeserializer.ReadInt() != 0)
			{
				Logger.LogError((object)"Missing 1st spacer trailer in SyncPersistentPlayerDataPackage.DeserializeData.");
				return;
			}
			if (binaryDeserializer.ReadInt() != -1535012113)
			{
				Logger.LogError((object)"Missing 1st spacer trailer in SyncPersistentPlayerDataPackage.DeserializeData.");
				return;
			}
			if (binaryDeserializer.ReadInt() != 1512782925)
			{
				Logger.LogError((object)"Missing 2nd spacer trailer in SyncPersistentPlayerDataPackage.DeserializeData.");
				return;
			}
			try
			{
				using StringReader stringReader = new StringReader(binaryDeserializer.ReadString(Encoding.UTF8));
				JsonTextReader val = new JsonTextReader((TextReader)stringReader);
				try
				{
					JObject val2 = (JObject)JToken.ReadFrom((JsonReader)(object)val);
					string name = ((object)val2["hat"])?.ToString() ?? string.Empty;
					if (string.IsNullOrEmpty(name))
					{
						Logger.LogError((object)"Hat name is null or empty, cannot set hat.");
						return;
					}
					Logger.LogDebug((object)$"Attempting to deserialize hat for player #{__instance.ActorNumber} to '{name}'");
					Customization customizationSingleton = Plugin.GetCustomizationSingleton();
					if ((Object)(object)customizationSingleton == (Object)null)
					{
						Logger.LogError((object)"Customization component not instantiated yet!");
						return;
					}
					CustomizationOption[] hats = customizationSingleton.hats;
					if (hats == null)
					{
						Logger.LogError((object)"No hats found in character customization, cannot set hat.");
						return;
					}
					int num = Array.FindIndex(hats, (CustomizationOption hat) => ((Object)hat).name == name);
					if (num >= 0)
					{
						__instance.Data.customizationData.currentHat = num;
						Logger.LogDebug((object)$"Deserialized hat for player #{__instance.ActorNumber} from '{name}' to #{num}");
					}
					else
					{
						Logger.LogError((object)$"Hat '{name}' not found in customization hats, cannot set hat for player #{__instance.ActorNumber}");
					}
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)$"Failed to deserialize hat for player #{__instance.ActorNumber} from JSON: {ex.Message}\n{ex.StackTrace}");
			}
		}

		[HarmonyPatch(typeof(PersistentPlayerDataService), "OnSyncReceived")]
		[HarmonyFinalizer]
		public static Exception? PersistentPlayerDataServiceOnSyncReceivedFinalizer(PersistentPlayerDataService __instance, SyncPersistentPlayerDataPackage package, Exception? __exception)
		{
			if (__exception != null)
			{
				Logger.LogWarning((object)("PersistentPlayerDataService.OnSyncReceived threw an exception\n" + __exception.GetType().FullName + ": " + __exception.Message + "\n" + __exception.StackTrace));
			}
			return null;
		}

		[HarmonyPatch(typeof(CharacterCustomization), "OnPlayerDataChange")]
		[HarmonyPostfix]
		public static void CharacterCustomizationOnPlayerDataChangePostfix(CharacterCustomization __instance, PersistentPlayerData playerData)
		{
			Logger.LogDebug((object)$"CharacterCustomization.OnPlayerDataChange called with hat index {playerData.customizationData.currentHat}");
			Plugin.BroadcastPluginEvent("OnAddHatsForCharacter", __instance._character);
		}

		[HarmonyPatch(typeof(CharacterCustomization), "OnPlayerDataChange")]
		[HarmonyFinalizer]
		public static Exception? CharacterCustomizationOnPlayerDataChangeFinalizer(CharacterCustomization __instance, Exception? __exception, PersistentPlayerData playerData)
		{
			if (__exception == null)
			{
				return null;
			}
			Logger.LogWarning((object)("CharacterCustomization.OnPlayerDataChange threw an exception\n" + __exception.GetType().FullName + ": " + __exception.Message + "\n" + __exception.StackTrace));
			return null;
		}

		[HarmonyPatch(typeof(PersistentPlayerDataService), "OnSyncReceived")]
		[HarmonyPostfix]
		public static void PersistentPlayerDataServiceOnSyncReceivedPostfix(PersistentPlayerDataService __instance, SyncPersistentPlayerDataPackage package)
		{
			Logger.LogDebug((object)"PersistentPlayerDataService.OnSyncReceived");
		}

		[HarmonyPatch(typeof(PersistentPlayerDataService), "SetPlayerData")]
		[HarmonyPostfix]
		public static void PersistentPlayerDataServiceSetPlayerDataPostfix(PersistentPlayerDataService __instance, Player player, PersistentPlayerData playerData)
		{
			Logger.LogDebug((object)"PersistentPlayerDataService.SetPlayerData");
		}

		[HarmonyPatch(typeof(PersistentPlayerDataService), "GetPlayerData", new Type[] { typeof(Player) })]
		[HarmonyPrefix]
		public static void PersistentPlayerDataServiceGetPlayerDataPrefix(PersistentPlayerDataService __instance, Player player)
		{
			Logger.LogDebug((object)"PersistentPlayerDataService.SetPlayerData(Player)");
		}

		[HarmonyPatch(typeof(PersistentPlayerDataService), "GetPlayerData", new Type[] { typeof(int) })]
		[HarmonyPrefix]
		public static void PersistentPlayerDataServiceGetPlayerDataPrefix(PersistentPlayerDataService __instance, int actorNumber)
		{
			Logger.LogDebug((object)"PersistentPlayerDataService.SetPlayerData(int)");
		}

		[HarmonyPatch(typeof(CharacterCustomization), "OnPlayerDataChange")]
		[HarmonyPrefix]
		public static void CharacterCustomizationOnPlayerDataChangePrefix(CharacterCustomization __instance, PersistentPlayerData playerData)
		{
			Logger.LogDebug((object)"CharacterCustomization.OnPlayerDataChange(int)");
			int currentHat = playerData.customizationData.currentHat;
			Renderer[] playerHats = __instance.refs.playerHats;
			if (playerHats != null && playerHats.Length != 0)
			{
				for (int i = 0; i < playerHats.Length; i++)
				{
					((Component)playerHats[i]).gameObject.SetActive(i == currentHat);
				}
			}
		}

		[HarmonyPatch(typeof(CharacterCustomization), "SetCustomizationForRef")]
		[HarmonyPrefix]
		public static void CharacterCustomizationSetCustomizationForRefPrefix(CustomizationRefs refs)
		{
			Logger.LogDebug((object)"CharacterCustomization.SetCustomizationForRef");
		}

		[HarmonyPatch(typeof(Character), "Awake")]
		[HarmonyPostfix]
		public static void CharacterAwakePostfix(Character __instance)
		{
			Plugin.BroadcastPluginEvent("OnAddHatsForCharacter", __instance);
		}

		[HarmonyPatch(typeof(Character), "Start")]
		[HarmonyPostfix]
		public static void CharacterStartPostfix(Character __instance)
		{
			Plugin.BroadcastPluginEvent("OnAddHatsForCharacter", __instance);
		}

		[HarmonyPatch(typeof(PlayerHandler), "RegisterCharacter")]
		[HarmonyPostfix]
		public static void PlayerHandlerRegisterCharacterPostfix(PlayerHandler __instance, Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				Logger.LogError((object)"PlayerHandler.RegisterCharacter called with null character, cannot add hats.");
				return;
			}
			Logger.LogDebug((object)$"PlayerHandler.RegisterCharacter called for {character.characterName} ({((MonoBehaviourPun)character).photonView.ViewID})");
			Plugin.BroadcastPluginEvent("OnAddHatsForCharacter", character);
		}

		[HarmonyPatch(typeof(CharacterCustomization), "Start")]
		[HarmonyPrefix]
		public static void CharacterCustomizationStartPrefix(CharacterCustomization __instance)
		{
			Logger.LogDebug((object)"CharacterCustomization.Start called");
			Plugin.BroadcastPluginEvent("OnLoadHats");
			Character character = __instance._character;
			if (!((Object)(object)character == (Object)null))
			{
				Plugin.BroadcastPluginEvent("OnAddHatsForCharacter", character);
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizationDummy), "UpdateDummy")]
		[HarmonyPrefix]
		public static void PlayerCustomizationDummyUpdateDummyPrefix(PlayerCustomizationDummy __instance)
		{
			Logger.LogDebug((object)"PlayerCustomizationDummy.UpdateDummy patch called");
			FixPlayerCustomizationData(__instance);
		}

		private static void FixPlayerCustomizationData(PlayerCustomizationDummy customizationDummy)
		{
			try
			{
				Plugin.BroadcastPluginEvent("OnLoadHats");
				Character localCharacter = Character.localCharacter;
				if ((Object)(object)localCharacter != (Object)null)
				{
					Plugin.BroadcastPluginEvent("OnAddHatsForCharacter", localCharacter);
				}
				PersistentPlayerDataService service = GameHandler.GetService<PersistentPlayerDataService>();
				bool flag = false;
				Customization customizationSingleton = Plugin.GetCustomizationSingleton();
				if ((Object)(object)customizationSingleton != (Object)null)
				{
					PersistentPlayerData playerData = service.GetPlayerData(PhotonNetwork.LocalPlayer);
					CharacterCustomizationData customizationData = playerData.customizationData;
					if (customizationData.currentSkin < 0 || customizationData.currentSkin > customizationSingleton.skins.Length)
					{
						customizationData.currentSkin = 0;
						flag = true;
					}
					if (customizationData.currentOutfit < 0 || customizationData.currentOutfit > customizationSingleton.fits.Length)
					{
						customizationData.currentOutfit = 0;
						flag = true;
					}
					if (customizationData.currentHat < 0 || customizationData.currentHat > customizationSingleton.hats.Length)
					{
						customizationData.currentHat = 0;
						flag = true;
					}
					if (customizationData.currentEyes < 0 || customizationData.currentEyes > customizationSingleton.eyes.Length)
					{
						customizationData.currentEyes = 0;
						flag = true;
					}
					if (customizationData.currentAccessory < 0 || customizationData.currentAccessory > customizationSingleton.accessories.Length)
					{
						customizationData.currentAccessory = 0;
						flag = true;
					}
					if (customizationData.currentMouth < 0 || customizationData.currentMouth > customizationSingleton.mouths.Length)
					{
						customizationData.currentMouth = 0;
						flag = true;
					}
					if (flag)
					{
						service.SetPlayerData(PhotonNetwork.LocalPlayer, playerData);
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("PlayerCustomizationDummy.UpdateDummy patch threw an exception\n" + ex.GetType().FullName + "\n" + ex.Message + "\n" + ex.StackTrace));
			}
		}

		[HarmonyPatch(typeof(PlayerCustomizationDummy), "UpdateDummy")]
		[HarmonyFinalizer]
		public static Exception? PlayerCustomizationDummyUpdateDummyFinalizer(PlayerCustomizationDummy __instance, Exception? __exception)
		{
			if (__exception == null)
			{
				return null;
			}
			if (__exception is IndexOutOfRangeException)
			{
				Logger.LogWarning((object)("PlayerCustomizationDummy.UpdateDummy threw an exception\n" + __exception.GetType().FullName + ": " + __exception.Message + "\n" + __exception.StackTrace));
				return null;
			}
			return __exception;
		}
	}
	[BepInPlugin("BobaHats", "BobaHats", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <LoadHatsFromBundle>d__14 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Plugin <>4__this;

			private AssetBundleCreateRequest <createRequest>5__2;

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

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

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

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

			private bool MoveNext()
			{
				//IL_026b: Unknown result type (might be due to invalid IL or missing references)
				//IL_025f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0275: Expected O, but got Unknown
				int num = <>1__state;
				Plugin plugin = <>4__this;
				bool flag;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					plugin.Logger.LogInfo((object)"Loading hats from bundle.");
					string text = Path.Combine(Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().Location).LocalPath), "bobacustomhats");
					if (!File.Exists(text))
					{
						plugin.Logger.LogError((object)("AssetBundle not found at " + text + ". Please ensure the file exists."));
						return false;
					}
					plugin.Logger.LogDebug((object)("Path to AssetBundle: " + text));
					<createRequest>5__2 = AssetBundle.LoadFromFileAsync(text);
					<>2__current = <createRequest>5__2;
					<>1__state = 1;
					return true;
				}
				case 1:
				{
					<>1__state = -1;
					AssetBundle assetBundle = <createRequest>5__2.assetBundle;
					plugin.Logger.LogInfo((object)"AssetBundle loaded.");
					assetBundle.GetAllAssetNames();
					Object[] array = assetBundle.LoadAllAssets();
					Object[] array2 = array;
					foreach (Object val in array2)
					{
						plugin.Logger.LogDebug((object)$"Asset: {val.name} ({((object)val).GetType()})");
					}
					plugin.Hats = (from x in array
						where (x is GameObject || x is Texture2D) ? true : false
						group x by x.name into x
						where x.Count() == 2
						select new Hat(x.Key, x.OfType<GameObject>().First(), x.OfType<Texture2D>().First())).ToArray();
					plugin.HatNames = new HashSet<string>(plugin.Hats.Select((Hat h) => h.Name));
					plugin.Logger.LogInfo((object)$"AssetBundle contains {plugin.Hats.Length} hats.");
					goto IL_021b;
				}
				case 2:
					{
						<>1__state = -1;
						if (Application.exitCancellationToken.IsCancellationRequested)
						{
							return false;
						}
						goto IL_021b;
					}
					IL_021b:
					flag = false;
					try
					{
						plugin.OnLoadHats();
					}
					catch (Exception ex)
					{
						plugin.Logger.LogError((object)("Failed to load hats: " + ex.Message + "\n" + ex.StackTrace));
						flag = true;
					}
					<>2__current = (object)(flag ? new WaitForSecondsRealtime(12f) : new WaitForSecondsRealtime(3f));
					<>1__state = 2;
					return true;
				}
			}

			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 Lazy<Shader> LazyCharacterShader = new Lazy<Shader>((Func<Shader>)(() => Shader.Find("W/Character")));

		[NonSerialized]
		public Hat[]? Hats;

		[NonSerialized]
		public HashSet<string>? HatNames;

		[NonSerialized]
		public bool HatsInserted;

		private const int HatInsertIndex = 23;

		public static Shader CharacterShader => LazyCharacterShader.Value;

		internal ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;

		public static Plugin? Instance { get; private set; }

		public void Awake()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Logger.LogInfo((object)"Plugin v1.0.0 is starting up.");
			new Harmony("BobaHats").PatchAll(typeof(BobaHatsPatches));
			((MonoBehaviour)this).StartCoroutine(LoadHatsFromBundle());
		}

		[IteratorStateMachine(typeof(<LoadHatsFromBundle>d__14))]
		private IEnumerator LoadHatsFromBundle()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadHatsFromBundle>d__14(0)
			{
				<>4__this = this
			};
		}

		internal static Customization? GetCustomizationSingleton()
		{
			return Singleton<Customization>.Instance;
		}

		internal static Character? GetCharacterByActorNumber(int actorNumber)
		{
			return ((IEnumerable<Character>)Character.AllCharacters).FirstOrDefault((Func<Character, bool>)((Character ch) => (Object)(object)((MonoBehaviourPun)ch).photonView != (Object)null && ((MonoBehaviourPun)ch).photonView.Owner != null && ((MonoBehaviourPun)ch).photonView.Owner.ActorNumber == actorNumber));
		}

		internal static Character? GetLocalCharacter()
		{
			return Character.localCharacter ?? GetCharacterByActorNumber(PhotonNetwork.LocalPlayer.ActorNumber);
		}

		public void OnLoadHats()
		{
			Plugin instance = Instance;
			if ((Object)(object)instance == (Object)null)
			{
				Logger.LogError((object)"Plugin instance not loaded yet, cannot instantiate hats!");
				return;
			}
			if (instance.Hats == null || instance.Hats.Length == 0 || HatNames == null || HatNames.Count == 0)
			{
				Logger.LogError((object)"No hats loaded, skipping instantiation!");
				return;
			}
			Customization customizationSingleton = GetCustomizationSingleton();
			if ((Object)(object)customizationSingleton == (Object)null)
			{
				Logger.LogError((object)"Customization component not instantiated yet!");
				return;
			}
			if (customizationSingleton.hats == null || customizationSingleton.hats.Length == 0)
			{
				Logger.LogError((object)"CustomizationOptions.hats is not populated yet, not adding hats!");
				return;
			}
			if (!customizationSingleton.hats.Skip(23).Any((CustomizationOption x) => HatNames.Contains(((Object)x).name)))
			{
				Logger.LogDebug((object)"Adding hat CustomizationOptions.");
				List<CustomizationOption> list = new List<CustomizationOption>(instance.Hats.Length);
				Hat[] hats = instance.Hats;
				for (int i = 0; i < hats.Length; i++)
				{
					Hat hat = hats[i];
					CustomizationOption val = CreateHatOption(hat.Name, hat.Icon);
					if ((Object)(object)val == (Object)null)
					{
						Logger.LogError((object)("Failed to create CustomizationOption for hat '" + hat.Name + "'."));
					}
					else
					{
						list.Add(val);
					}
				}
				HatsInserted = true;
				ArrayInsert(ref customizationSingleton.hats, 23, list);
				Logger.LogDebug((object)"Completed adding hats to Customization Options.");
			}
			PlayerCustomizationDummy dummy = PassportManager.instance.dummy;
			Transform val2 = TransformExtensions.FindChildRecursive(((Component)dummy).transform, "Hat");
			if ((Object)(object)val2 == (Object)null)
			{
				Logger.LogError((object)"Dummy hat container not found, cannot instantiate hats for dummy.");
				return;
			}
			if (!HatsInserted)
			{
				Logger.LogError((object)"HatsInserted is not set yet, not instantiating hats!");
				return;
			}
			ref Renderer[] playerHats = ref dummy.refs.playerHats;
			if (!playerHats.Skip(23).Any((Renderer x) => HatNames.Contains(((Object)x).name)))
			{
				Renderer val3 = playerHats.FirstOrDefault();
				Renderer obj = playerHats[0];
				object obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					MeshRenderer componentInChildren = ((Component)obj).GetComponentInChildren<MeshRenderer>(true);
					obj2 = ((componentInChildren != null) ? ((Renderer)componentInChildren).material : null);
				}
				Material dummyHatMat = (Material)obj2;
				Material obj3 = dummyHatMat;
				Dictionary<string, float> dictionary = ((obj3 != null) ? obj3.GetPropertyNames((MaterialPropertyType)0).ToDictionary((string n) => n, (string n) => dummyHatMat.GetFloat(n)) : null);
				if ((Object)(object)val3 == (Object)null)
				{
					Logger.LogDebug((object)"Dummy is missing hats - something is wrong, aborting...");
					return;
				}
				int layer = ((Component)val3).gameObject.layer;
				Logger.LogDebug((object)$"Instantiating hats for dummy as children of {val2}.");
				List<Renderer> list2 = new List<Renderer>(instance.Hats.Length);
				Hat[] hats = instance.Hats;
				for (int i = 0; i < hats.Length; i++)
				{
					Hat hat2 = hats[i];
					if ((Object)(object)hat2.Prefab == (Object)null)
					{
						Logger.LogError((object)("Hat prefab for '" + hat2.Name + "' is null, skipping instantiation for dummy."));
						continue;
					}
					GameObject val4 = Object.Instantiate<GameObject>(hat2.Prefab, val2);
					((Object)val4).name = hat2.Name;
					GameObjectExtensions.SetLayerRecursivly(val4, layer);
					MeshRenderer[] componentsInChildren = val4.GetComponentsInChildren<MeshRenderer>(true);
					for (int j = 0; j < componentsInChildren.Length; j++)
					{
						Material material = ((Renderer)componentsInChildren[j]).material;
						material.enableInstancing = true;
						((Object)material).hideFlags = (HideFlags)32;
						material.shader = CharacterShader;
						if (dictionary == null)
						{
							continue;
						}
						foreach (KeyValuePair<string, float> item in dictionary)
						{
							material.SetFloat(item.Key, item.Value);
						}
					}
					Renderer componentInChildren2 = val4.GetComponentInChildren<Renderer>();
					((Component)componentInChildren2).gameObject.SetActive(false);
					list2.Add(componentInChildren2);
				}
				ArrayInsert(ref playerHats, 23, list2);
				Logger.LogDebug((object)"Completed adding hats to Passport dummy.");
			}
			Character localCharacter = GetLocalCharacter();
			AddHatsForCharacter(localCharacter);
			if (GameHandler.GetService<PersistentPlayerDataService>() == null)
			{
				Logger.LogError((object)"PersistentPlayerDataService is null, cannot set hat.");
			}
		}

		private static void ArrayInsert<T>(ref T[]? array, int insertIndex, IReadOnlyList<T>? toAdd)
		{
			if (toAdd == null || toAdd.Count == 0)
			{
				return;
			}
			if (array == null || array.Length == 0)
			{
				array = toAdd.ToArray();
				return;
			}
			if (insertIndex < 0 || insertIndex > array.Length)
			{
				throw new ArgumentOutOfRangeException("insertIndex", $"Insert index ({insertIndex}) is out of bounds.");
			}
			T[] array2 = new T[array.Length + toAdd.Count];
			if (insertIndex == array.Length)
			{
				array.CopyTo(array2, 0);
				for (int i = 0; i < toAdd.Count; i++)
				{
					array2[i + insertIndex] = toAdd[i];
				}
			}
			else
			{
				Array.Copy(array, 0, array2, 0, insertIndex);
				for (int j = 0; j < toAdd.Count; j++)
				{
					array2[j + insertIndex] = toAdd[j];
				}
				int destinationIndex = insertIndex + toAdd.Count;
				int length = array.Length - insertIndex;
				Array.Copy(array, insertIndex, array2, destinationIndex, length);
			}
			array = array2;
		}

		private static void ArrayAppend<T>(ref T[]? array, IReadOnlyList<T>? toAdd)
		{
			if (toAdd == null || toAdd.Count == 0)
			{
				return;
			}
			if (array == null || array.Length == 0)
			{
				array = toAdd.ToArray();
				return;
			}
			T[] array2 = new T[array.Length + toAdd.Count];
			array.CopyTo(array2, 0);
			for (int i = 0; i < toAdd.Count; i++)
			{
				array2[i + array.Length] = toAdd[i];
			}
			array = array2;
		}

		private void AddHatsForCharacter(Character? character)
		{
			Plugin instance = Instance;
			if ((Object)(object)instance == (Object)null || HatNames == null || instance.Hats == null || instance.Hats.Length == 0)
			{
				Logger.LogError((object)"Plugin instance or hats not loaded yet, cannot instantiate hats!");
				return;
			}
			if (!HatsInserted)
			{
				Logger.LogError((object)"HatsInserted is not set yet, not instantiating hats!");
				return;
			}
			if ((Object)(object)character == (Object)null)
			{
				Logger.LogError((object)"Local character not found, cannot instantiate hats!");
				return;
			}
			CharacterRefs refs = character.refs;
			if (refs == null)
			{
				Logger.LogError((object)$"Character #{((MonoBehaviourPun)character).photonView.Owner.ActorNumber} '{((Object)character).name}' is missing refs!");
				return;
			}
			CharacterCustomization customization = refs.customization;
			if ((Object)(object)customization == (Object)null)
			{
				Logger.LogError((object)$"Character #{((MonoBehaviourPun)character).photonView.Owner.ActorNumber} '{((Object)character).name}' is missing a customization component!");
				return;
			}
			ref Renderer[] playerHats = ref customization.refs.playerHats;
			if (playerHats == null)
			{
				Logger.LogError((object)$"Character #{((MonoBehaviourPun)character).photonView.Owner.ActorNumber} '{((Object)character).name}' is missing hats on the customization component!");
				return;
			}
			if (playerHats.Skip(23).Any((Renderer x) => HatNames.Contains(((Object)x).name)))
			{
				Logger.LogDebug((object)$"Character #{((MonoBehaviourPun)character).photonView.Owner.ActorNumber} '{((Object)character).name}' already has hats, skipping.");
				return;
			}
			Logger.LogDebug((object)$"Adding hats to Character #{((MonoBehaviourPun)character).photonView.Owner.ActorNumber} '{((Object)character).name}'");
			Transform val = TransformExtensions.FindChildRecursive(((Component)customization).transform, "Hat");
			Logger.LogDebug((object)$"Hats container found: {val} (inst #{((Object)val).GetInstanceID()})");
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogError((object)"Hats container not found, cannot instantiate hats.");
				return;
			}
			Logger.LogDebug((object)$"Instantiating hats as children of {val} (inst #{((Object)val).GetInstanceID()})");
			Renderer obj = playerHats[0];
			object obj2;
			if (obj == null)
			{
				obj2 = null;
			}
			else
			{
				MeshRenderer componentInChildren = ((Component)obj).GetComponentInChildren<MeshRenderer>(true);
				obj2 = ((componentInChildren != null) ? ((Renderer)componentInChildren).material : null);
			}
			Material hatMat = (Material)obj2;
			Material obj3 = hatMat;
			Dictionary<string, float> dictionary = ((obj3 != null) ? obj3.GetPropertyNames((MaterialPropertyType)0).ToDictionary((string n) => n, (string n) => hatMat.GetFloat(n)) : null);
			List<Renderer> list = new List<Renderer>(instance.Hats.Length);
			Hat[] hats = instance.Hats;
			for (int i = 0; i < hats.Length; i++)
			{
				Hat hat = hats[i];
				if ((Object)(object)hat.Prefab == (Object)null)
				{
					Logger.LogError((object)("Hat prefab for '" + hat.Name + "' is null, skipping instantiation."));
					continue;
				}
				GameObject val2 = Object.Instantiate<GameObject>(hat.Prefab, val);
				((Object)val2).name = hat.Name;
				MeshRenderer[] componentsInChildren = val2.GetComponentsInChildren<MeshRenderer>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					Material material = ((Renderer)componentsInChildren[j]).material;
					material.enableInstancing = true;
					((Object)material).hideFlags = (HideFlags)32;
					material.shader = CharacterShader;
					if (dictionary == null)
					{
						continue;
					}
					foreach (KeyValuePair<string, float> item in dictionary)
					{
						material.SetFloat(item.Key, item.Value);
					}
				}
				Renderer componentInChildren2 = val2.GetComponentInChildren<Renderer>();
				((Component)componentInChildren2).gameObject.SetActive(false);
				list.Add(componentInChildren2);
			}
			ArrayInsert(ref playerHats, 23, list);
			Logger.LogDebug((object)$"Completed adding hats to Character #{((MonoBehaviourPun)character).photonView.Owner.ActorNumber} '{((Object)character).name}'");
		}

		public static CustomizationOption CreateHatOption(string hatName, Texture2D icon)
		{
			//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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			CustomizationOption obj = ScriptableObject.CreateInstance<CustomizationOption>();
			obj.color = Color.white;
			((Object)obj).name = hatName;
			obj.texture = (Texture)(object)icon;
			obj.type = (Type)50;
			obj.requiredAchievement = (ACHIEVEMENTTYPE)0;
			return obj;
		}

		public static void OnAddHatsForCharacter(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				Plugin? instance = Instance;
				if (instance != null)
				{
					instance.Logger.LogError((object)"OnAddHatsForCharacter called for null character.");
				}
				return;
			}
			Plugin? instance2 = Instance;
			if (instance2 != null)
			{
				instance2.Logger.LogDebug((object)$"OnAddHatsForCharacter called for character #{((MonoBehaviourPun)character).photonView.Owner.ActorNumber} '{((Object)character).name}'");
			}
			Instance?.AddHatsForCharacter(character);
		}

		public static void BroadcastPluginEvent(string message)
		{
			Plugin instance = Instance;
			BaseUnityPlugin[] array = Resources.FindObjectsOfTypeAll<BaseUnityPlugin>();
			foreach (BaseUnityPlugin val in array)
			{
				Type type = ((object)val).GetType();
				MethodInfo method = type.GetMethod(message, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Any, Array.Empty<Type>(), null);
				if (!(method == null))
				{
					if (instance != null)
					{
						instance.Logger.LogDebug((object)("Calling " + method.Name + " on plugin " + type.FullName));
					}
					method.Invoke(method.IsStatic ? null : val, Array.Empty<object>());
				}
			}
		}

		public static void BroadcastPluginEvent(string message, params object[] args)
		{
			string message2 = message;
			object[] args2 = args;
			if (args2 == null)
			{
				throw new ArgumentNullException("args");
			}
			Plugin instance = Instance;
			BaseUnityPlugin[] array = Resources.FindObjectsOfTypeAll<BaseUnityPlugin>();
			foreach (BaseUnityPlugin val in array)
			{
				Type type = ((object)val).GetType();
				MethodInfo methodInfo = (MethodInfo)type.GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MemberInfo m) => m.Name == message2 && m is MethodInfo mi && HasCompatibleParameters(mi, args2));
				if (!(methodInfo == null))
				{
					if (instance != null)
					{
						instance.Logger.LogDebug((object)("Calling " + methodInfo.Name + " on plugin " + type.FullName));
					}
					methodInfo.Invoke(methodInfo.IsStatic ? null : val, args2);
				}
			}
		}

		private static bool HasCompatibleParameters(MethodInfo mi, object[] args)
		{
			ParameterInfo[] parameters = mi.GetParameters();
			if (parameters.Length != args.Length)
			{
				return false;
			}
			for (int i = 0; i < args.Length; i++)
			{
				if (!IsCompatibleParameter(parameters[i].ParameterType, args[i]))
				{
					return false;
				}
			}
			return true;
		}

		private static bool IsCompatibleParameter(Type paramType, object? arg)
		{
			if (arg == null)
			{
				if (paramType.IsValueType)
				{
					return Nullable.GetUnderlyingType(paramType) != null;
				}
				return true;
			}
			if (!paramType.IsInstanceOfType(arg))
			{
				if (paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable<>))
				{
					return Nullable.GetUnderlyingType(paramType).IsInstanceOfType(arg);
				}
				return false;
			}
			return true;
		}
	}
	public struct Hat
	{
		public string Name;

		public GameObject Prefab;

		public Texture2D Icon;

		public Hat(string name, GameObject prefab, Texture2D icon)
		{
			Name = name;
			Prefab = prefab;
			Icon = icon;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "BobaHats";

		public const string PLUGIN_NAME = "BobaHats";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		internal IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}