Decompiled source of ExtraCompany v1.0.0

plugins/ExtraCompany/aj.ExtraHeads.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DunGen;
using ExtraHeads.Configuration;
using ExtraHeads.Cosmetics;
using ExtraHeads.UI;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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("aj.ExtraHeads")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ExtraCompany")]
[assembly: AssemblyTitle("aj.ExtraHeads")]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was created with the assistance of generative AI (code); see the README credits for which assets.")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 ExtraHeads
{
	[HarmonyPatch]
	internal static class GameFixes
	{
		[HarmonyPatch(typeof(StartOfRound), "OnClientConnect")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> FreeSlotSearch(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "OnClientConnect", 1, Il.LoopTo4, Il.Slots);
		}

		[HarmonyPatch(typeof(StartOfRound), "SyncShipUnlockablesServerRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SuitsServer(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "SyncShipUnlockablesServerRpc", 2, (List<CodeInstruction> c, int i) => Il.NewArrayOf4(c, i) || Il.LoopTo4(c, i), Il.Slots);
		}

		[HarmonyPatch(typeof(StartOfRound), "SyncShipUnlockablesClientRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SuitsClient(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "SyncShipUnlockablesClientRpc", 1, Il.LoopTo4, Il.Slots);
		}

		[HarmonyPatch(typeof(HUDManager), "SyncAllPlayerLevelsServerRpc", new Type[] { })]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Levels(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "SyncAllPlayerLevelsServerRpc", 2, Il.NewArrayOf4, Il.Slots);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "SendNewPlayerValuesServerRpc")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Names(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "SendNewPlayerValuesServerRpc", 1, Il.LoopTo4, Il.Slots);
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> CameraCheck(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "PlayerControllerB.Update", 1, (List<CodeInstruction> c, int i) => Il.IsConst(c[i], 4) && i > 0 && Il.LoadsLocal(c[i - 1]) && i + 1 < c.Count && (c[i + 1].opcode == OpCodes.Bne_Un || c[i + 1].opcode == OpCodes.Bne_Un_S), Il.Slots);
		}

		[HarmonyPatch(typeof(EnemyAI), "TargetClosestPlayer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> TargetEverySlot(IEnumerable<CodeInstruction> code)
		{
			return LoopOverGaps(code, "TargetClosestPlayer");
		}

		[HarmonyPatch(typeof(RoundManager), "AverageOfLivingGroupedPlayerPositions")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> AverageEverySlot(IEnumerable<CodeInstruction> code)
		{
			return LoopOverGaps(code, "AverageOfLivingGroupedPlayerPositions");
		}

		private static IEnumerable<CodeInstruction> LoopOverGaps(IEnumerable<CodeInstruction> code, string where)
		{
			Label? label = default(Label?);
			return Il.Swap(code, where, 1, (List<CodeInstruction> c, int i) => c[i].opcode == OpCodes.Add && i >= 2 && Il.IsConst(c[i - 1], 1) && Il.Loads(c[i - 2], "connectedPlayersAmount") && i + 1 < c.Count && CodeInstructionExtensions.Branches(c[i + 1], ref label), () => (CodeInstruction[])(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Add, (object)null),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(LobbySize), "LoopEnd", (Type[])null, (Type[])null))
			});
		}

		[HarmonyPatch(typeof(QuickMenuManager), "AddUserToPlayerList")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ListRows(IEnumerable<CodeInstruction> code)
		{
			Label? label = default(Label?);
			return Il.Swap(code, "AddUserToPlayerList", 1, (List<CodeInstruction> c, int i) => Il.IsConst(c[i], 4) && i + 1 < c.Count && CodeInstructionExtensions.Branches(c[i + 1], ref label), () => (CodeInstruction[])(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(GameFixes), "LastListRow", (Type[])null, (Type[])null))
			});
		}

		public static int LastListRow(QuickMenuManager menu)
		{
			return menu.playerListSlots.Length - 1;
		}

		[HarmonyPatch(typeof(QuickMenuManager), "RemoveUserFromPlayerList")]
		[HarmonyPrefix]
		private static bool OnlyListedRows(QuickMenuManager __instance, int playerObjectId)
		{
			if (playerObjectId >= 0)
			{
				return playerObjectId < __instance.playerListSlots.Length;
			}
			return false;
		}

		[HarmonyPatch(typeof(QuickMenuManager), "ConfirmKickUserFromServer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> KickAnyone(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "ConfirmKickUserFromServer", 1, (List<CodeInstruction> c, int i) => Il.IsConst(c[i], 3) && i > 0 && Il.Loads(c[i - 1], "playerObjToKick"), Il.LastSlot);
		}

		[HarmonyPatch(typeof(HUDManager), "AddChatMessage")]
		[HarmonyPrefix]
		private static void NameEveryone(ref string chatMessage)
		{
			if (LobbySize.Expanded && !string.IsNullOrEmpty(chatMessage) && chatMessage.Contains("[playerNum"))
			{
				PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
				StringBuilder stringBuilder = new StringBuilder(chatMessage);
				for (int i = 4; i < allPlayerScripts.Length; i++)
				{
					stringBuilder.Replace($"[playerNum{i}]", allPlayerScripts[i].playerUsername);
				}
				chatMessage = stringBuilder.ToString();
			}
		}

		[HarmonyPatch(typeof(HUDManager), "FillEndGameStats")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ResultsRows(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "FillEndGameStats", 1, (List<CodeInstruction> c, int i) => c[i].opcode == OpCodes.Ldlen && i > 0 && Il.Loads(c[i - 1], "allPlayerScripts"), () => (CodeInstruction[])(object)new CodeInstruction[3]
			{
				new CodeInstruction(OpCodes.Ldlen, (object)null),
				new CodeInstruction(OpCodes.Conv_I4, (object)null),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(GameFixes), "ShownResults", (Type[])null, (Type[])null))
			});
		}

		public static int ShownResults(int players)
		{
			return Mathf.Min(players, HUDManager.Instance.statsUIElements.playerNamesText.Length);
		}
	}
	[HarmonyPatch]
	internal static class IdleSlots
	{
		private static readonly Dictionary<PlayerControllerB, List<Behaviour>> parked = new Dictionary<PlayerControllerB, List<Behaviour>>();

		private static readonly FieldRef<PlayerControllerB, bool> CameraDisabled = AccessTools.FieldRefAccess<PlayerControllerB, bool>("isCameraDisabled");

		private static bool Empty(PlayerControllerB player)
		{
			if (!player.isPlayerControlled)
			{
				return !player.isPlayerDead;
			}
			return false;
		}

		[HarmonyPatch(typeof(StartOfRound), "Update")]
		[HarmonyPostfix]
		private static void ParkEmptySlots(StartOfRound __instance)
		{
			if (!LobbySize.Expanded || __instance.allPlayerScripts == null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = __instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				if (Empty(val) && CameraDisabled.Invoke(val))
				{
					if (!parked.ContainsKey(val))
					{
						parked[val] = SwitchOffScripts(val);
					}
					Switch(val, on: false);
				}
				else
				{
					if (!parked.TryGetValue(val, out List<Behaviour> value))
					{
						continue;
					}
					parked.Remove(val);
					Switch(val, on: true);
					foreach (Behaviour item in value)
					{
						if ((Object)(object)item != (Object)null)
						{
							item.enabled = true;
						}
					}
				}
			}
		}

		private static List<Behaviour> SwitchOffScripts(PlayerControllerB player)
		{
			List<Behaviour> list = new List<Behaviour>();
			Behaviour[] componentsInChildren = ((Component)player).GetComponentsInChildren<Behaviour>();
			foreach (Behaviour val in componentsInChildren)
			{
				if (val.enabled && !(val is NetworkBehaviour) && !(val is NetworkObject) && !(val is Camera) && !(val is AudioListener))
				{
					val.enabled = false;
					list.Add(val);
				}
			}
			return list;
		}

		private static void Switch(PlayerControllerB player, bool on)
		{
			if ((Object)(object)player.thisController != (Object)null && ((Collider)player.thisController).enabled != on)
			{
				((Collider)player.thisController).enabled = on;
			}
			Switch((Renderer?)(object)player.thisPlayerModel, on);
			Switch((Renderer?)(object)player.thisPlayerModelLOD1, on);
			Switch((Renderer?)(object)player.thisPlayerModelLOD2, on);
		}

		private static void Switch(Renderer? body, bool on)
		{
			if ((Object)(object)body != (Object)null && body.enabled != on)
			{
				body.enabled = on;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")]
		[HarmonyPrefix]
		private static bool RunUnlessEmpty(PlayerControllerB __instance)
		{
			if (LobbySize.Expanded && Empty(__instance))
			{
				return !CameraDisabled.Invoke(__instance);
			}
			return true;
		}

		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		[HarmonyPostfix]
		private static void Forget()
		{
			parked.Clear();
		}
	}
	internal static class Il
	{
		internal static IEnumerable<CodeInstruction> Swap(IEnumerable<CodeInstruction> instructions, string where, int expected, Func<List<CodeInstruction>, int, bool> isPlayerCount, Func<CodeInstruction[]> replacement)
		{
			List<CodeInstruction> list = instructions.ToList();
			List<int> list2 = new List<int>();
			for (int i = 0; i < list.Count; i++)
			{
				if (isPlayerCount(list, i))
				{
					list2.Add(i);
				}
			}
			if (list2.Count != expected)
			{
				Plugin.Logger.LogWarning((object)$"{where}: expected {expected} player count(s), found {list2.Count}; left unchanged (game update?).");
				return list;
			}
			for (int num = list2.Count - 1; num >= 0; num--)
			{
				int index = list2[num];
				CodeInstruction[] array = replacement();
				array[0].labels.AddRange(list[index].labels);
				array[0].blocks.AddRange(list[index].blocks);
				list.RemoveAt(index);
				list.InsertRange(index, array);
			}
			return list;
		}

		internal static bool IsConst(CodeInstruction ci, int value)
		{
			return CodeInstructionExtensions.LoadsConstant(ci, (long)value);
		}

		internal static bool Loads(CodeInstruction ci, string field)
		{
			if ((ci.opcode == OpCodes.Ldfld || ci.opcode == OpCodes.Ldsfld) && ci.operand is FieldInfo fieldInfo)
			{
				return fieldInfo.Name == field;
			}
			return false;
		}

		internal static bool Calls(CodeInstruction ci, string method)
		{
			if ((ci.opcode == OpCodes.Call || ci.opcode == OpCodes.Callvirt) && ci.operand is MethodBase methodBase)
			{
				return methodBase.Name == method;
			}
			return false;
		}

		internal static bool LoadsLocal(CodeInstruction ci)
		{
			return ci.opcode.Name.StartsWith("ldloc");
		}

		internal static bool NewArrayOf4(List<CodeInstruction> c, int i)
		{
			if (IsConst(c[i], 4) && i + 1 < c.Count)
			{
				return c[i + 1].opcode == OpCodes.Newarr;
			}
			return false;
		}

		internal static bool LoopTo4(List<CodeInstruction> c, int i)
		{
			Label? label = default(Label?);
			if (IsConst(c[i], 4) && i > 0 && LoadsLocal(c[i - 1]) && i + 1 < c.Count)
			{
				return CodeInstructionExtensions.Branches(c[i + 1], ref label);
			}
			return false;
		}

		internal static CodeInstruction[] Slots()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return (CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(LobbySize), "Slots"))
			};
		}

		internal static CodeInstruction[] LastSlot()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return (CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(LobbySize), "LastSlot"))
			};
		}
	}
	[HarmonyPatch]
	internal static class Joining
	{
		internal const string LobbyKey = "extraheads";

		private const string PayloadTag = "ExtraHeads";

		private const string SizeReason = "EXTRAHEADS_SIZE:";

		private const float LanRetryDelay = 1f;

		private static bool retryAtHostSize;

		[HarmonyPatch(typeof(GameNetworkManager), "StartHost")]
		[HarmonyPrefix]
		private static void HostAtConfigSize()
		{
			LobbySize.Set(Plugin.BoundConfig.LobbySize.Value, "hosting");
			GameNetworkManager.Instance.maxAllowedPlayers = LobbySize.Limit;
		}

		[HarmonyPatch(typeof(SteamMatchmaking), "CreateLobbyAsync")]
		[HarmonyPrefix]
		private static void LobbyRoom(ref int maxMembers)
		{
			maxMembers = LobbySize.Limit;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "SteamMatchmaking_OnLobbyCreated")]
		[HarmonyPostfix]
		private static void MarkLobby(Lobby lobby)
		{
			((Lobby)(ref lobby)).SetData("extraheads", "1.0.0");
		}

		[HarmonyPatch(typeof(GameNetworkManager), "LobbyDataIsJoinable")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> FullAtLobbyRoom(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "LobbyDataIsJoinable", 1, (List<CodeInstruction> c, int i) => Il.IsConst(c[i], 4) && i > 0 && Il.Calls(c[i - 1], "get_MemberCount"), () => (CodeInstruction[])(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Ldarg_1, (object)null),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(LobbySize), "RoomOf", (Type[])null, (Type[])null))
			});
		}

		[HarmonyPatch(typeof(GameNetworkManager), "LobbyDataIsJoinable")]
		[HarmonyPostfix]
		private static void TakeLobbySize(Lobby lobby, ref bool __result)
		{
			if (!__result)
			{
				return;
			}
			string data = ((Lobby)(ref lobby)).GetData("extraheads");
			if (string.IsNullOrEmpty(data))
			{
				if (((Lobby)(ref lobby)).MaxMembers > 4)
				{
					__result = Refuse("This lobby uses a different player-count mod, not Extra Heads.");
				}
				else
				{
					LobbySize.Set(4, "joining a normal lobby");
				}
			}
			else if (data != "1.0.0")
			{
				__result = Refuse("The host has Extra Heads " + data + "; you have 1.0.0.");
			}
			else
			{
				LobbySize.Set(((Lobby)(ref lobby)).MaxMembers, "joining a Steam lobby");
			}
		}

		private static bool Refuse(string why)
		{
			MenuManager obj = Object.FindObjectOfType<MenuManager>();
			if (obj != null)
			{
				obj.SetLoadingScreen(false, (RoomEnter)5, why);
			}
			return false;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "SetConnectionDataBeforeConnecting")]
		[HarmonyPostfix]
		private static void TagConnectionData()
		{
			NetworkConfig networkConfig = NetworkManager.Singleton.NetworkConfig;
			string s = Encoding.ASCII.GetString(networkConfig.ConnectionData) + string.Format(",{0}:{1}:{2}", "ExtraHeads", "1.0.0", LobbySize.Slots);
			networkConfig.ConnectionData = Encoding.ASCII.GetBytes(s);
		}

		[HarmonyPatch(typeof(GameNetworkManager), "ConnectionApproval")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> FullAtLimit(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "ConnectionApproval", 1, (List<CodeInstruction> c, int i) => Il.IsConst(c[i], 4) && i > 0 && Il.Loads(c[i - 1], "connectedPlayers"), () => (CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(LobbySize), "Limit"))
			});
		}

		[HarmonyPatch(typeof(GameNetworkManager), "ConnectionApproval")]
		[HarmonyPostfix]
		[HarmonyBefore(new string[] { "LateLanding" })]
		private static void CheckJoiner(ConnectionApprovalRequest request, ConnectionApprovalResponse response)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (response.Approved && request.ClientNetworkId != NetworkManager.Singleton.LocalClientId)
			{
				string text = JoinerProblem(Encoding.ASCII.GetString(request.Payload));
				if (text != null)
				{
					response.Approved = false;
					response.Reason = text;
					Plugin.Logger.LogInfo((object)$"Refused joiner {request.ClientNetworkId}: {text}");
				}
			}
		}

		private static string? JoinerProblem(string payload)
		{
			string text = payload.Split(',').FirstOrDefault((string part) => part.StartsWith("ExtraHeads:"));
			if (text == null)
			{
				if (!LobbySize.Expanded)
				{
					return null;
				}
				return $"This lobby holds {LobbySize.Limit} players and needs the Extra Heads mod.";
			}
			string[] array = text.Split(':');
			string text2 = ((array.Length > 1) ? array[1] : "?");
			if (text2 != "1.0.0")
			{
				return "ExtraCompany version mismatch: the host has 1.0.0, you have " + text2 + ".";
			}
			if (array.Length < 3 || !int.TryParse(array[2], out var result) || result != LobbySize.Slots)
			{
				return "EXTRAHEADS_SIZE:" + LobbySize.Slots;
			}
			return null;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "OnLocalClientConnectionDisapproved")]
		[HarmonyPrefix]
		private static void ReadSizeRefusal()
		{
			NetworkManager singleton = NetworkManager.Singleton;
			string text = ((singleton != null) ? singleton.DisconnectReason : null);
			if (text != null && text.StartsWith("EXTRAHEADS_SIZE:") && int.TryParse(text.Substring("EXTRAHEADS_SIZE:".Length), out var result))
			{
				LobbySize.Set(result, "the host's lobby size");
				retryAtHostSize = true;
			}
		}

		[HarmonyPatch(typeof(GameNetworkManager), "OnLocalClientConnectionDisapproved")]
		[HarmonyPostfix]
		private static void RetryAtHostSize(GameNetworkManager __instance)
		{
			if (!retryAtHostSize)
			{
				return;
			}
			retryAtHostSize = false;
			__instance.disconnectionReasonMessage = "";
			if (__instance.disableSteam)
			{
				((MonoBehaviour)__instance).StartCoroutine(JoinLanAgain());
				return;
			}
			MenuManager obj = Object.FindObjectOfType<MenuManager>();
			if (obj != null)
			{
				obj.SetLoadingScreen(false, (RoomEnter)5, $"The lobby now holds {LobbySize.Slots} players. Join again.");
			}
		}

		private static IEnumerator JoinLanAgain()
		{
			yield return (object)new WaitForSeconds(1f);
			MenuManager val = Object.FindObjectOfType<MenuManager>();
			if ((Object)(object)val != (Object)null)
			{
				Plugin.Logger.LogInfo((object)$"Joining the LAN host again at its lobby size ({LobbySize.Slots}).");
				val.StartAClient();
			}
		}
	}
	[HarmonyPatch]
	internal static class LoadingSpeed
	{
		private const float FrameBudgetMs = 40f;

		private static readonly Stopwatch building = new Stopwatch();

		private static int frames;

		[HarmonyPatch(typeof(RoundManager), "GenerateNewFloor")]
		[HarmonyPrefix]
		private static void BuildFaster(RoundManager __instance)
		{
			DungeonGenerator val = __instance.dungeonGenerator?.Generator;
			if (val != null)
			{
				if (Plugin.BoundConfig.FastLoading.Value && val.GenerateAsynchronously)
				{
					val.MaxAsyncFrameMilliseconds = 40f;
				}
				frames = Time.frameCount;
				building.Restart();
			}
		}

		[HarmonyPatch(typeof(RoundManager), "FinishGeneratingLevel")]
		[HarmonyPostfix]
		private static void Built()
		{
			if (building.IsRunning)
			{
				building.Stop();
				Plugin.Logger.LogInfo((object)($"Facility built in {building.Elapsed.TotalSeconds:0.00} s over {Time.frameCount - frames} frames " + "(fast loading " + (Plugin.BoundConfig.FastLoading.Value ? "on" : "off") + ")."));
			}
		}
	}
	internal static class LobbySize
	{
		internal const int Vanilla = 4;

		internal const int Ceiling = 16;

		internal const int Smallest = 1;

		public static int Limit { get; private set; } = 4;

		public static int Slots { get; private set; } = 4;

		public static int LastSlot => Slots - 1;

		internal static bool Expanded => Slots > 4;

		public static int AllSeenShortcut
		{
			get
			{
				if (!Expanded)
				{
					return 4;
				}
				return -1;
			}
		}

		internal static void Set(int size, string why)
		{
			int num = Mathf.Clamp(size, 1, 16);
			int num2 = Mathf.Clamp(size, 4, 16);
			if (num != Limit || num2 != Slots)
			{
				Plugin.Logger.LogInfo((object)$"Lobby size {Limit} -> {num}, player slots {Slots} -> {num2} ({why}).");
			}
			Limit = num;
			Slots = num2;
		}

		public static int RoomOf(Lobby lobby)
		{
			if (!string.IsNullOrEmpty(((Lobby)(ref lobby)).GetData("extraheads")))
			{
				return Mathf.Clamp(((Lobby)(ref lobby)).MaxMembers, 1, 16);
			}
			return 4;
		}

		public static int LoopEnd(int vanillaEnd)
		{
			if (!Expanded)
			{
				return vanillaEnd;
			}
			return Slots;
		}
	}
	[HarmonyPatch]
	internal static class MonsterFixes
	{
		[HarmonyPatch(typeof(EnemyAI), "GetClosestPlayer")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ClosestOfAll(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "EnemyAI.GetClosestPlayer", 1, Il.LoopTo4, Il.Slots);
		}

		[HarmonyPatch(typeof(EnemyAI), "GetAllPlayersInLineOfSight")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> SeenAreSeen(IEnumerable<CodeInstruction> code)
		{
			return NoAllSeenShortcut(code, "EnemyAI.GetAllPlayersInLineOfSight");
		}

		[HarmonyPatch(typeof(CaveDwellerAI), "GetAllPlayerBodiesInLineOfSight")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ManeaterSeenAreSeen(IEnumerable<CodeInstruction> code)
		{
			return NoAllSeenShortcut(code, "CaveDwellerAI.GetAllPlayerBodiesInLineOfSight");
		}

		private static IEnumerable<CodeInstruction> NoAllSeenShortcut(IEnumerable<CodeInstruction> code, string where)
		{
			return Il.Swap(code, where, 1, (List<CodeInstruction> c, int i) => Il.IsConst(c[i], 4) && i > 0 && Il.Calls(c[i - 1], "get_Count"), () => (CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)AccessTools.PropertyGetter(typeof(LobbySize), "AllSeenShortcut"))
			});
		}

		[HarmonyPatch(typeof(BushWolfEnemy), "GetClosestPlayerToNest")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> FoxNest(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "BushWolfEnemy.GetClosestPlayerToNest", 1, Il.LoopTo4, Il.Slots);
		}

		[HarmonyPatch(typeof(SpringManAI), "Update")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> CoilHeadWatchers(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "SpringManAI.Update", 1, Il.LoopTo4, Il.Slots);
		}

		[HarmonyPatch(typeof(DressGirlAI), "ChoosePlayerToHaunt")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> GhostGirlChoice(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "DressGirlAI.ChoosePlayerToHaunt", 3, (List<CodeInstruction> c, int i) => Il.LoopTo4(c, i) || Il.NewArrayOf4(c, i), Il.Slots);
		}

		[HarmonyPatch(typeof(ForestGiantAI), "Start")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> GiantStealth(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "ForestGiantAI.Start", 1, Il.NewArrayOf4, Il.Slots);
		}

		[HarmonyPatch(typeof(ButlerEnemyAI), "Start")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ButlerMemory(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "ButlerEnemyAI.Start", 3, Il.NewArrayOf4, Il.Slots);
		}

		[HarmonyPatch(typeof(BlobAI), "Start")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> HygrodereBodies(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "BlobAI.Start", 1, Il.NewArrayOf4, Il.Slots);
		}

		[HarmonyPatch(typeof(CrawlerAI), "Start")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> ThumperReach(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "CrawlerAI.Start", 1, Il.NewArrayOf4, Il.Slots);
		}

		[HarmonyPatch(typeof(ShipTeleporter), "Awake")]
		[HarmonyPostfix]
		private static void TeleportAnyone(ref int[] ___playersBeingTeleported)
		{
			int num = ___playersBeingTeleported.Length;
			if (num < LobbySize.Slots)
			{
				Array.Resize(ref ___playersBeingTeleported, LobbySize.Slots);
				for (int i = num; i < LobbySize.Slots; i++)
				{
					___playersBeingTeleported[i] = -1;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class OtherExpanders
	{
		private static bool done;

		internal static bool Found { get; private set; }

		[HarmonyPatch(typeof(MenuManager), "Start")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void StepAsideIfAnother()
		{
			if (!done)
			{
				done = true;
				MethodInfo methodInfo = AccessTools.Method(typeof(NetworkSceneManager), "PopulateScenePlacedObjects", (Type[])null, (Type[])null);
				Patches val = ((methodInfo != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo) : null);
				HashSet<string> hashSet = ((val != null) ? new HashSet<string>(val.Owners) : new HashSet<string>());
				hashSet.Remove("ExtraCompany");
				if (hashSet.Count != 0)
				{
					Found = true;
					Plugin.Logger.LogError((object)("Another mod also adds player slots (" + string.Join(", ", hashSet) + "): Extra Heads stays off. Remove one of the two; they can't run together."));
					Plugin.Harmony.UnpatchSelf();
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class PlayerSlots
	{
		private const uint HashBase = 1162346496u;

		private const uint HashStride = 32u;

		private const float SpawnSpacing = 0.7f;

		private static readonly FieldRef<NetworkObject, uint> GlobalHash = AccessTools.FieldRefAccess<NetworkObject, uint>("GlobalObjectIdHash");

		private static readonly FieldRef<PlayerControllerB, Collider[]> NearByPlayers = AccessTools.FieldRefAccess<PlayerControllerB, Collider[]>("nearByPlayers");

		[HarmonyPatch(typeof(NetworkSceneManager), "PopulateScenePlacedObjects")]
		[HarmonyPostfix]
		private static void AddExtraPlayers(Dictionary<uint, Dictionary<int, NetworkObject>> ___ScenePlacedObjects)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Expected O, but got Unknown
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || instance.allPlayerObjects.Length >= LobbySize.Slots)
			{
				return;
			}
			int num = instance.allPlayerObjects.Length;
			int slots = LobbySize.Slots;
			GameObject val = instance.allPlayerObjects[num - 1];
			Array.Resize(ref instance.allPlayerObjects, slots);
			Array.Resize(ref instance.allPlayerScripts, slots);
			Array.Resize(ref instance.gameStats.allPlayerStats, slots);
			Array.Resize(ref instance.playerSpawnPositions, slots);
			for (int i = num; i < slots; i++)
			{
				GameObject val2 = Object.Instantiate<GameObject>(val, val.transform.parent);
				((Object)val2).name = $"Player ({i})";
				NetworkObject[] componentsInChildren = val2.GetComponentsInChildren<NetworkObject>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					uint num2 = (uint)(1162346496 + i * 32 + j);
					GlobalHash.Invoke(componentsInChildren[j]) = num2;
					Scene scene = ((Component)componentsInChildren[j]).gameObject.scene;
					int handle = ((Scene)(ref scene)).handle;
					if (!___ScenePlacedObjects.TryGetValue(num2, out Dictionary<int, NetworkObject> value))
					{
						value = (___ScenePlacedObjects[num2] = new Dictionary<int, NetworkObject>());
					}
					value[handle] = componentsInChildren[j];
				}
				PlayerControllerB componentInChildren = val2.GetComponentInChildren<PlayerControllerB>();
				componentInChildren.playerClientId = (ulong)i;
				componentInChildren.playerUsername = $"Player #{i}";
				componentInChildren.isPlayerControlled = false;
				componentInChildren.isPlayerDead = false;
				componentInChildren.TeleportPlayer(instance.notSpawnedPosition.position, false, 0f, false, true);
				instance.allPlayerObjects[i] = val2;
				instance.allPlayerScripts[i] = componentInChildren;
				instance.gameStats.allPlayerStats[i] = new PlayerStats();
				instance.playerSpawnPositions[i] = ExtraSpawnSpot(instance, i);
				instance.mapScreen.radarTargets.Add(new TransformAndName(((Component)componentInChildren).transform, componentInChildren.playerUsername, false));
			}
			Plugin.Logger.LogInfo((object)$"Player slots {num} -> {slots}.");
		}

		private static Transform ExtraSpawnSpot(StartOfRound round, int slot)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			Transform val = round.playerSpawnPositions[slot % 4];
			int num = (slot - 4) / 4;
			float num2 = ((num % 2 == 0) ? 1f : (-1f)) * 0.7f * (float)(num / 2 + 1);
			Vector3 val2 = val.position + val.right * num2;
			Bounds bounds = round.shipInnerRoomBounds.bounds;
			Vector3 val3 = ((Bounds)(ref bounds)).ClosestPoint(val2);
			Transform transform = new GameObject($"ExtraHeads spawn {slot}").transform;
			transform.SetParent(val.parent, true);
			transform.SetPositionAndRotation(new Vector3(val3.x, val.position.y, val3.z), val.rotation);
			return transform;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Start")]
		[HarmonyPostfix]
		private static void RoomForEveryone(PlayerControllerB __instance)
		{
			if (LobbySize.Expanded)
			{
				NearByPlayers.Invoke(__instance) = (Collider[])(object)new Collider[LobbySize.Slots];
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "NearOtherPlayers")]
		[HarmonyPrefix]
		private static bool SkipEmptySlots(PlayerControllerB __instance, float checkRadius, ref bool __result)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (!LobbySize.Expanded)
			{
				return true;
			}
			__result = false;
			PlayerControllerB[] array = StartOfRound.Instance?.allPlayerScripts;
			if (array == null)
			{
				return false;
			}
			float num = checkRadius * checkRadius;
			PlayerControllerB[] array2 = array;
			foreach (PlayerControllerB val in array2)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)__instance && val.isPlayerControlled)
				{
					Vector3 val2 = ((Component)__instance).transform.position - ((Component)val).transform.position;
					if (((Vector3)(ref val2)).sqrMagnitude < num)
					{
						__result = true;
						break;
					}
				}
			}
			return false;
		}

		[HarmonyPatch(typeof(StartOfRound), "GetPlayerSpawnPosition")]
		[HarmonyFinalizer]
		private static Exception? SpawnFallback(Exception? __exception, StartOfRound __instance, ref Vector3 __result)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (__exception is IndexOutOfRangeException && LobbySize.Expanded)
			{
				__result = __instance.playerSpawnPositions[0].position + Vector3.up * 0.5f;
				return null;
			}
			return __exception;
		}
	}
	[BepInPlugin("ExtraCompany", "ExtraCompany", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		internal static PluginConfig BoundConfig { get; private set; }

		internal static Harmony Harmony { get; private set; }

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			BoundConfig = new PluginConfig(((BaseUnityPlugin)this).Config);
			Harmony = new Harmony("ExtraCompany");
			Harmony.PatchAll(typeof(OtherExpanders));
			Harmony.PatchAll(typeof(Joining));
			Harmony.PatchAll(typeof(PlayerSlots));
			Harmony.PatchAll(typeof(IdleSlots));
			Harmony.PatchAll(typeof(GameFixes));
			Harmony.PatchAll(typeof(Voice));
			Harmony.PatchAll(typeof(MonsterFixes));
			Harmony.PatchAll(typeof(LoadingSpeed));
			Harmony.PatchAll(typeof(LobbyPicker));
			Harmony.PatchAll(typeof(PlayerList));
			Harmony.PatchAll(typeof(ResultsGrid));
			Harmony.PatchAll(typeof(SpectatorList));
			Harmony.PatchAll(typeof(Wardrobe));
			Harmony.PatchAll(typeof(CosmeticPicker));
			Logger.LogInfo((object)"Plugin ExtraCompany is loaded!");
		}
	}
	[HarmonyPatch]
	internal static class Voice
	{
		private const float PitchLerpSpeed = 3f;

		private const float NeutralPitch = 1f;

		private const float StartVolume = 0.5f;

		[HarmonyPatch(typeof(SoundManager), "Start")]
		[HarmonyPostfix]
		private static void VoiceForEveryone(SoundManager __instance)
		{
			if (LobbySize.Expanded)
			{
				int slots = LobbySize.Slots;
				Grow(ref __instance.playerVoicePitchLerpSpeed, slots, 3f);
				Grow(ref __instance.playerVoicePitchTargets, slots, 1f);
				Grow(ref __instance.playerVoicePitches, slots, 1f);
				Grow(ref __instance.playerVoiceVolumes, slots, 0.5f);
				AudioMixerGroup[] playerVoiceMixers = __instance.playerVoiceMixers;
				int num = playerVoiceMixers.Length;
				Array.Resize(ref __instance.playerVoiceMixers, slots);
				for (int i = num; i < slots; i++)
				{
					__instance.playerVoiceMixers[i] = playerVoiceMixers[i % num];
				}
			}
		}

		private static void Grow(ref float[] values, int slots, float fill)
		{
			int num = values.Length;
			if (num < slots)
			{
				Array.Resize(ref values, slots);
				for (int i = num; i < slots; i++)
				{
					values[i] = fill;
				}
			}
		}

		[HarmonyPatch(typeof(SoundManager), "SetPlayerVoiceFilters")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> OnlyRealChannels(IEnumerable<CodeInstruction> code)
		{
			return Il.Swap(code, "SetPlayerVoiceFilters", 2, (List<CodeInstruction> c, int i) => c[i].opcode == OpCodes.Ldlen && i > 0 && Il.Loads(c[i - 1], "allPlayerScripts"), () => (CodeInstruction[])(object)new CodeInstruction[3]
			{
				new CodeInstruction(OpCodes.Ldlen, (object)null),
				new CodeInstruction(OpCodes.Conv_I4, (object)null),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Voice), "MixerChannels", (Type[])null, (Type[])null))
			});
		}

		public static int MixerChannels(int players)
		{
			return Mathf.Min(players, 4);
		}

		[HarmonyPatch(typeof(SoundManager), "SetPlayerPitch")]
		[HarmonyPrefix]
		private static bool OnlyRealPitch(int playerObjNum)
		{
			return playerObjNum < 4;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "ExtraCompany";

		public const string PLUGIN_NAME = "ExtraCompany";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace ExtraHeads.UI
{
	[HarmonyPatch]
	internal static class CosmeticPicker
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Close;
		}

		private const float CellShare = 0.15f;

		private const float PadShare = 0.025f;

		private const float HeaderShare = 0.11f;

		private const float FooterShare = 0.09f;

		private const int Columns = 5;

		private const float NameSize = 0.024f;

		private const float TitleSize = 0.05f;

		private const float HintSize = 0.026f;

		private const float ButtonTextSize = 0.032f;

		private static readonly Color Backdrop = new Color(0f, 0f, 0f, 0.6f);

		private static readonly Color Panel = new Color(0.12f, 0.02f, 0.01f, 0.97f);

		private static readonly Color Cell = new Color(0.22f, 0.05f, 0.03f, 1f);

		private static readonly Color CellWorn = new Color(0.55f, 0.2f, 0.05f, 1f);

		private static readonly Color Orange = new Color(1f, 0.45f, 0.1f, 1f);

		private const string ButtonName = "ExtraHeads Cosmetics Button";

		private const string PanelName = "ExtraHeads Cosmetics";

		private static GameObject? open;

		[HarmonyPatch(typeof(MenuManager), "Start")]
		[HarmonyPostfix]
		private static void MainMenuButton(MenuManager __instance)
		{
			if (!__instance.isInitScene && !((Object)(object)__instance.menuButtons == (Object)null) && !OtherExpanders.Found)
			{
				AddButton(__instance.menuButtons.transform);
			}
		}

		[HarmonyPatch(typeof(QuickMenuManager), "Start")]
		[HarmonyPostfix]
		private static void PauseMenuButton(QuickMenuManager __instance)
		{
			if ((Object)(object)__instance.mainButtonsPanel != (Object)null)
			{
				AddButton(__instance.mainButtonsPanel.transform);
			}
		}

		[HarmonyPatch(typeof(QuickMenuManager), "CloseQuickMenu")]
		[HarmonyPostfix]
		private static void CloseWithPauseMenu()
		{
			Close();
		}

		private static void AddButton(Transform buttons)
		{
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			//IL_0177: Expected O, but got Unknown
			CosmeticLibrary.Load();
			if (CosmeticLibrary.All.Count == 0 || (Object)(object)buttons.Find("ExtraHeads Cosmetics Button") != (Object)null)
			{
				return;
			}
			Transform val = ((IEnumerable)buttons).Cast<Transform>().FirstOrDefault((Func<Transform, bool>)delegate(Transform b)
			{
				TMP_Text componentInChildren = ((Component)b).GetComponentInChildren<TMP_Text>(true);
				return componentInChildren != null && componentInChildren.text.ToLowerInvariant().Contains("settings");
			});
			if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).GetComponent<Button>() == (Object)null)
			{
				Plugin.Logger.LogWarning((object)("No Settings button in " + ((Object)buttons).name + "; no Cosmetics button there."));
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, buttons, false);
			((Object)val2).name = "ExtraHeads Cosmetics Button";
			TMP_Text label = val2.GetComponentInChildren<TMP_Text>(true);
			label.text = Regex.Replace(label.text, "settings", (Match m) => (!(m.Value == "SETTINGS")) ? ((!(m.Value == "settings")) ? "Cosmetics" : "cosmetics") : "COSMETICS", RegexOptions.IgnoreCase);
			Button component = val2.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				Open(buttons, label);
			});
			val2.transform.SetSiblingIndex(val.GetSiblingIndex() + 1);
			if ((Object)(object)((Component)buttons).GetComponent<LayoutGroup>() == (Object)null)
			{
				Respace(buttons, (RectTransform)val, (RectTransform)val2.transform);
			}
		}

		private static void Respace(Transform buttons, RectTransform settings, RectTransform ours)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			List<RectTransform> list = (from RectTransform c in (IEnumerable)buttons
				where (Object)(object)c != (Object)(object)ours && ((Component)c).gameObject.activeSelf && (Object)(object)((Component)c).GetComponentInChildren<Button>() != (Object)null
				select c).OrderByDescending(RowY).ToList();
			if (list.Count < 2 || !list.Contains(settings))
			{
				RectTransform obj = ours;
				Vector2 anchoredPosition = settings.anchoredPosition;
				Rect rect = settings.rect;
				obj.anchoredPosition = anchoredPosition - new Vector2(0f, ((Rect)(ref rect)).height * 1.2f);
				return;
			}
			float num = RowY(list[0]);
			float num2 = RowY(list[list.Count - 1]);
			Dictionary<RectTransform, float> dictionary = list.ToDictionary((RectTransform c) => c, RowY);
			ours.anchoredPosition = settings.anchoredPosition;
			dictionary[ours] = dictionary[settings];
			list.Insert(list.IndexOf(settings) + 1, ours);
			float num3 = (num - num2) / (float)(list.Count - 1);
			for (int num4 = 0; num4 < list.Count; num4++)
			{
				RectTransform obj2 = list[num4];
				obj2.anchoredPosition += new Vector2(0f, num - (float)num4 * num3 - dictionary[list[num4]]);
			}
			float RowY(RectTransform row)
			{
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				return buttons.InverseTransformPoint(((Component)((Component)row).GetComponentInChildren<Button>()).transform.position).y;
			}
		}

		internal static void Open(Transform near, TMP_Text style)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: 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)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Expected O, but got Unknown
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Expected O, but got Unknown
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Expected O, but got Unknown
			Close();
			Canvas componentInParent = ((Component)near).GetComponentInParent<Canvas>();
			Canvas val = ((componentInParent != null) ? componentInParent.rootCanvas : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			RectTransform val2 = (RectTransform)((Component)val).transform;
			Rect rect = val2.rect;
			float height = ((Rect)(ref rect)).height;
			float num = height * 0.15f;
			float num2 = height * 0.025f;
			int num3 = Mathf.CeilToInt((float)CosmeticLibrary.All.Count / 5f);
			float num4 = 5f * num + 6f * num2;
			float num5 = height * 0.11f + (float)num3 * num + (float)(num3 - 1) * num2 + height * 0.09f + num2;
			RectTransform val3 = Rect("ExtraHeads Cosmetics", (Transform)(object)val2, Backdrop);
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			Vector2 offsetMin = (val3.offsetMax = Vector2.zero);
			val3.offsetMin = offsetMin;
			open = ((Component)val3).gameObject;
			RectTransform val4 = Rect("Panel", (Transform)(object)val3, Panel);
			val4.sizeDelta = new Vector2(num4, num5);
			((Shadow)((Component)val4).gameObject.AddComponent<Outline>()).effectColor = Orange;
			Label(val4, "Title", "COSMETICS", style, height * 0.05f, new Vector2(0f, num5 / 2f - height * 0.11f * 0.38f), num4, Orange);
			Label(val4, "Hint", "Click to wear or take off. Any mix; everyone sees them.", style, height * 0.026f, new Vector2(0f, num5 / 2f - height * 0.11f * 0.82f), num4, new Color(1f, 0.8f, 0.6f));
			HashSet<string> worn = new HashSet<string>(Wardrobe.Split(Wardrobe.LocalWorn));
			List<(string id, Image bg, Outline edge)> cells = new List<(string, Image, Outline)>();
			float num6 = num5 / 2f - height * 0.11f - num / 2f;
			Vector2 anchoredPosition = default(Vector2);
			for (int i = 0; i < CosmeticLibrary.All.Count; i++)
			{
				CosmeticLibrary.Cosmetic cosmetic = CosmeticLibrary.All[i];
				((Vector2)(ref anchoredPosition))..ctor((0f - num4) / 2f + num2 + num / 2f + (float)(i % 5) * (num + num2), num6 - (float)(i / 5) * (num + num2));
				RectTransform val5 = Rect(cosmetic.Id, (Transform)(object)val4, Cell);
				val5.sizeDelta = new Vector2(num, num);
				val5.anchoredPosition = anchoredPosition;
				Outline val6 = ((Component)val5).gameObject.AddComponent<Outline>();
				((Shadow)val6).effectDistance = new Vector2(2f, 2f);
				if ((Object)(object)cosmetic.Icon != (Object)null)
				{
					RectTransform obj = Rect("Icon", (Transform)(object)val5, Color.white);
					Image component = ((Component)obj).GetComponent<Image>();
					component.sprite = cosmetic.Icon;
					component.preserveAspect = true;
					((Graphic)component).raycastTarget = false;
					obj.sizeDelta = new Vector2(num * 0.6f, num * 0.6f);
					obj.anchoredPosition = new Vector2(0f, num * 0.17f);
				}
				Label(val5, "Name", cosmetic.Name, style, height * 0.024f, new Vector2(0f, (0f - num) * 0.32f), num * 0.94f, Color.white, 2);
				Button obj2 = ((Component)val5).gameObject.AddComponent<Button>();
				((Selectable)obj2).targetGraphic = (Graphic)(object)((Component)val5).GetComponent<Image>();
				string id = cosmetic.Id;
				((UnityEvent)obj2.onClick).AddListener((UnityAction)delegate
				{
					if (!worn.Remove(id))
					{
						worn.Add(id);
					}
					Wardrobe.SetLocal(string.Join(",", worn));
					Paint(cells, worn);
				});
				cells.Add((cosmetic.Id, ((Component)val5).GetComponent<Image>(), val6));
			}
			Paint(cells, worn);
			float num7 = (0f - num5) / 2f + num2 + height * 0.09f * 0.45f;
			TextButton(val4, "Take all off", style, height, new Vector2((0f - num4) / 4f, num7), (UnityAction)delegate
			{
				worn.Clear();
				Wardrobe.SetLocal("");
				Paint(cells, worn);
			});
			Vector2 pos = new Vector2(num4 / 4f, num7);
			object obj3 = <>O.<0>__Close;
			if (obj3 == null)
			{
				UnityAction val7 = Close;
				<>O.<0>__Close = val7;
				obj3 = (object)val7;
			}
			TextButton(val4, "Done", style, height, pos, (UnityAction)obj3);
		}

		private static void Paint(List<(string id, Image bg, Outline edge)> cells, HashSet<string> worn)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			foreach (var cell in cells)
			{
				string item = cell.id;
				Image item2 = cell.bg;
				Outline item3 = cell.edge;
				bool flag = worn.Contains(item);
				((Graphic)item2).color = (flag ? CellWorn : Cell);
				((Shadow)item3).effectColor = (flag ? Orange : Color.clear);
			}
		}

		internal static void Close()
		{
			if ((Object)(object)open != (Object)null)
			{
				Object.Destroy((Object)(object)open);
				open = null;
			}
		}

		private static RectTransform Rect(string name, Transform parent, Color colour)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			}).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			component.pivot = val;
			Vector2 anchorMin = (component.anchorMax = val);
			component.anchorMin = anchorMin;
			((Graphic)((Component)component).GetComponent<Image>()).color = colour;
			return component;
		}

		private static void Label(RectTransform parent, string name, string text, TMP_Text style, float size, Vector2 pos, float width, Color colour, int lines = 1)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = new GameObject(name, new Type[1] { typeof(RectTransform) }).AddComponent<TextMeshProUGUI>();
			RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
			((Transform)rectTransform).SetParent((Transform)(object)parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			rectTransform.pivot = val;
			Vector2 anchorMin = (rectTransform.anchorMax = val);
			rectTransform.anchorMin = anchorMin;
			rectTransform.anchoredPosition = pos;
			rectTransform.sizeDelta = new Vector2(width, size * ((lines == 1) ? 1.4f : (1.2f * (float)lines)));
			((TMP_Text)obj).font = style.font;
			((TMP_Text)obj).fontSharedMaterial = style.fontSharedMaterial;
			((Graphic)obj).color = colour;
			((TMP_Text)obj).enableAutoSizing = true;
			((TMP_Text)obj).fontSizeMax = size;
			((TMP_Text)obj).fontSizeMin = size * ((lines == 1) ? 0.5f : 0.8f);
			((TMP_Text)obj).alignment = (TextAlignmentOptions)514;
			((TMP_Text)obj).enableWordWrapping = lines > 1;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).text = text;
		}

		private static void TextButton(RectTransform parent, string text, TMP_Text style, float h, Vector2 pos, UnityAction act)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = Rect(text, (Transform)(object)parent, Cell);
			val.sizeDelta = new Vector2(h * 0.26f, h * 0.06f);
			val.anchoredPosition = pos;
			((Shadow)((Component)val).gameObject.AddComponent<Outline>()).effectColor = Orange;
			Label(val, "Text", text, style, h * 0.032f, Vector2.zero, h * 0.25f, Orange);
			Button obj = ((Component)val).gameObject.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)((Component)val).GetComponent<Image>();
			((UnityEvent)obj.onClick).AddListener(act);
		}
	}
	[HarmonyPatch]
	internal static class LobbyPicker
	{
		private const float ExtraHeight = 34f;

		private const float RowY = -19f;

		private const float LabelX = -68f;

		private const float LabelWidth = 110f;

		private const float FieldX = 24f;

		private const float FieldWidth = 48f;

		private const float RangeX = 88f;

		private const float RangeWidth = 60f;

		private const float LabelSize = 13f;

		private const float RangeSize = 11f;

		private const int Digits = 2;

		private const string RowName = "ExtraHeads LobbySize";

		private static TMP_InputField? field;

		[HarmonyPatch(typeof(MenuManager), "Start")]
		[HarmonyPostfix]
		private static void AddPicker(MenuManager __instance)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.isInitScene || (Object)(object)__instance.HostSettingsScreen == (Object)null || OtherExpanders.Found)
			{
				return;
			}
			Transform val = __instance.HostSettingsScreen.transform.Find("HostSettingsContainer");
			Transform val2 = ((val != null) ? val.Find("Back") : null);
			Transform val3 = ((val != null) ? val.Find("Confirm") : null);
			object obj;
			if (val == null)
			{
				obj = null;
			}
			else
			{
				Transform obj2 = val.Find("LobbyHostOptions/LANOptions/Header");
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<TextMeshProUGUI>() : null);
			}
			TextMeshProUGUI val4 = (TextMeshProUGUI)obj;
			Transform val5 = ((val != null) ? val.Find("LobbyHostOptions/OptionsNormal/ServerNameField") : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val.Find("ExtraHeads LobbySize") != (Object)null)
			{
				Plugin.Logger.LogWarning((object)"Host settings screen not as expected; no lobby size box.");
				return;
			}
			RectTransform val6 = (RectTransform)val;
			val6.sizeDelta += new Vector2(0f, 34f);
			foreach (Transform item in val)
			{
				Transform val7 = item;
				RectTransform val8 = (RectTransform)val7;
				if ((Object)(object)val7 == (Object)(object)val3 || (Object)(object)val7 == (Object)(object)val2)
				{
					val8.anchoredPosition -= new Vector2(0f, 17f);
				}
				else if (((Object)val7).name == "LobbyHostOptions")
				{
					val8.anchoredPosition += new Vector2(0f, 17f);
				}
			}
			RectTransform component = new GameObject("ExtraHeads LobbySize", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(val, false);
			Vector2 val9 = default(Vector2);
			((Vector2)(ref val9))..ctor(0.5f, 0.5f);
			component.pivot = val9;
			Vector2 anchorMin = (component.anchorMax = val9);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(0f, -19f);
			component.sizeDelta = new Vector2(val6.sizeDelta.x, 34f);
			Text(component, "Label", "Lobby size:", val4, 13f, -68f, 110f, (TextAlignmentOptions)516);
			Text(component, "Range", $"({1}-{16})", val4, 11f, 88f, 60f, (TextAlignmentOptions)513);
			field = NumberBox(component, val5);
		}

		private static TMP_InputField NumberBox(RectTransform row, Transform template)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			GameObject obj = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)row, false);
			((Object)obj).name = "Size";
			obj.SetActive(true);
			RectTransform val = (RectTransform)obj.transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.anchoredPosition = new Vector2(24f, 0f);
			val.sizeDelta = new Vector2(48f / ((Transform)val).localScale.x, val.sizeDelta.y);
			TMP_InputField component = obj.GetComponent<TMP_InputField>();
			component.onValueChanged = new OnChangeEvent();
			component.onEndEdit = new SubmitEvent();
			component.onSubmit = new SubmitEvent();
			component.contentType = (ContentType)2;
			component.characterLimit = 2;
			component.textComponent.alignment = (TextAlignmentOptions)514;
			Graphic placeholder = component.placeholder;
			TMP_Text val4 = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null);
			if (val4 != null)
			{
				val4.text = 4.ToString();
				val4.alignment = (TextAlignmentOptions)514;
			}
			component.text = Plugin.BoundConfig.LobbySize.Value.ToString();
			((UnityEvent<string>)(object)component.onEndEdit).AddListener((UnityAction<string>)Take);
			return component;
		}

		private static void Take(string typed)
		{
			ConfigEntry<int> lobbySize = Plugin.BoundConfig.LobbySize;
			if (int.TryParse(typed, out var result))
			{
				lobbySize.Value = Mathf.Clamp(result, 1, 16);
			}
			if ((Object)(object)field != (Object)null)
			{
				field.SetTextWithoutNotify(lobbySize.Value.ToString());
			}
		}

		private static void Text(RectTransform row, string name, string text, TextMeshProUGUI style, float size, float x, float width, TextAlignmentOptions align)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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)
			TextMeshProUGUI obj = new GameObject(name, new Type[1] { typeof(RectTransform) }).AddComponent<TextMeshProUGUI>();
			RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
			((Transform)rectTransform).SetParent((Transform)(object)row, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			rectTransform.pivot = val;
			Vector2 anchorMin = (rectTransform.anchorMax = val);
			rectTransform.anchorMin = anchorMin;
			rectTransform.anchoredPosition = new Vector2(x, 0f);
			rectTransform.sizeDelta = new Vector2(width, row.sizeDelta.y);
			((TMP_Text)obj).font = ((TMP_Text)style).font;
			((TMP_Text)obj).fontSharedMaterial = ((TMP_Text)style).fontSharedMaterial;
			((Graphic)obj).color = ((Graphic)style).color;
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).alignment = align;
			((TMP_Text)obj).enableWordWrapping = false;
			((TMP_Text)obj).text = text;
		}
	}
	[HarmonyPatch]
	internal static class PlayerList
	{
		private const float RowSpacing = 64f;

		private const float RowTop = 64f;

		private const float ListTop = 58f;

		private const float ListBottom = 10f;

		private const float ScrollSpeed = 24f;

		private const string ListName = "ExtraHeads Crew";

		private static TextMeshProUGUI? header;

		private static RectTransform? rows;

		[HarmonyPatch(typeof(QuickMenuManager), "Start")]
		[HarmonyPostfix]
		private static void ListEveryone(QuickMenuManager __instance)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			if (!LobbySize.Expanded)
			{
				return;
			}
			PlayerListSlot[] playerListSlots = __instance.playerListSlots;
			Transform val = __instance.playerListPanel.transform.Find("Image");
			object obj;
			if (val == null)
			{
				obj = null;
			}
			else
			{
				Transform obj2 = val.Find("Header");
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<TextMeshProUGUI>() : null);
			}
			header = (TextMeshProUGUI?)obj;
			if ((Object)(object)val == (Object)null || playerListSlots.Length == 0 || (Object)(object)playerListSlots[0].slotContainer == (Object)null || (Object)(object)val.Find("ExtraHeads Crew") != (Object)null)
			{
				Plugin.Logger.LogWarning((object)"Pause-menu crew list not as expected; extra players get no rows.");
				return;
			}
			RectTransform component = new GameObject("ExtraHeads Crew", new Type[4]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(RectMask2D),
				typeof(ScrollRect)
			}).GetComponent<RectTransform>();
			((Graphic)((Component)component).GetComponent<Image>()).color = Color.clear;
			((Transform)component).SetParent(val, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = new Vector2(0f, 10f);
			component.offsetMax = new Vector2(0f, -58f);
			RectTransform component2 = new GameObject("Rows", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component2).SetParent((Transform)(object)component, false);
			component2.anchorMin = new Vector2(0f, 1f);
			component2.anchorMax = new Vector2(1f, 1f);
			component2.pivot = new Vector2(0.5f, 1f);
			component2.anchoredPosition = Vector2.zero;
			component2.sizeDelta = new Vector2(0f, (float)LobbySize.Slots * 64f);
			rows = component2;
			ScrollRect component3 = ((Component)component).GetComponent<ScrollRect>();
			component3.content = component2;
			component3.viewport = component;
			component3.horizontal = false;
			component3.movementType = (MovementType)2;
			component3.scrollSensitivity = 24f;
			int num = playerListSlots.Length;
			Array.Resize(ref __instance.playerListSlots, LobbySize.Slots);
			GameObject slotContainer = playerListSlots[num - 1].slotContainer;
			Vector2 val3 = default(Vector2);
			for (int i = 0; i < LobbySize.Slots; i++)
			{
				if (i >= num)
				{
					__instance.playerListSlots[i] = CopyRow(__instance, slotContainer, i);
				}
				RectTransform val2 = (RectTransform)__instance.playerListSlots[i].slotContainer.transform;
				((Transform)val2).SetParent((Transform)(object)component2, false);
				((Vector2)(ref val3))..ctor(0.5f, 1f);
				val2.anchorMax = val3;
				val2.anchorMin = val3;
				val2.anchoredPosition = new Vector2(val2.anchoredPosition.x, -64f - (float)i * 64f);
			}
		}

		private static PlayerListSlot CopyRow(QuickMenuManager menu, GameObject template, int slot)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(template, template.transform.parent, false);
			((Object)val).name = $"PlayerListSlot ({slot})";
			val.SetActive(false);
			PlayerListSlot entry = new PlayerListSlot
			{
				slotContainer = val,
				usernameHeader = ((Component)val.transform.Find("PlayerNameButton/PName")).GetComponent<TextMeshProUGUI>(),
				volumeSliderContainer = ((Component)val.transform.Find("VoiceVolumeSlider")).gameObject,
				volumeSlider = ((Component)val.transform.Find("VoiceVolumeSlider/Slider")).GetComponent<Slider>(),
				KickUserButton = ((Component)val.transform.Find("KickButton")).gameObject,
				isConnected = false
			};
			Button component = entry.KickUserButton.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				menu.KickUserFromServer(slot);
			});
			Transform obj = val.transform.Find("ProfileIcon");
			Button val2 = ((obj != null) ? ((Component)obj).GetComponent<Button>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.onClick = new ButtonClickedEvent();
				((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
				{
					//IL_0024: Unknown result type (might be due to invalid IL or missing references)
					if (!GameNetworkManager.Instance.disableSteam && entry.playerSteamId != 0L)
					{
						SteamFriends.OpenUserOverlay(SteamId.op_Implicit(entry.playerSteamId), "steamid");
					}
				});
			}
			return entry;
		}

		[HarmonyPatch(typeof(QuickMenuManager), "Update")]
		[HarmonyPostfix]
		private static void CountCrew(QuickMenuManager __instance)
		{
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)header == (Object)null || !LobbySize.Expanded || !__instance.isMenuOpen)
			{
				return;
			}
			int num = (((Object)(object)StartOfRound.Instance != (Object)null) ? (StartOfRound.Instance.connectedPlayersAmount + 1) : 0);
			PlayerListSlot[] playerListSlots = __instance.playerListSlots;
			for (int i = 0; i < Preview.Players && i < playerListSlots.Length; i++)
			{
				if (!playerListSlots[i].isConnected)
				{
					playerListSlots[i].slotContainer.SetActive(true);
					((TMP_Text)playerListSlots[i].usernameHeader).text = Preview.Name(i);
				}
			}
			((TMP_Text)header).text = $"CREW: {Mathf.Max(num, Preview.Players)} / {LobbySize.Slots}";
			if ((Object)(object)rows == (Object)null)
			{
				return;
			}
			int num2 = 0;
			PlayerListSlot[] array = playerListSlots;
			foreach (PlayerListSlot val in array)
			{
				if ((Object)(object)val.slotContainer != (Object)null && val.slotContainer.activeSelf)
				{
					RectTransform val2 = (RectTransform)val.slotContainer.transform;
					val2.anchoredPosition = new Vector2(val2.anchoredPosition.x, -64f - (float)num2 * 64f);
					num2++;
				}
			}
			rows.sizeDelta = new Vector2(0f, (float)num2 * 64f + 10f);
		}
	}
	internal static class Preview
	{
		internal static int Players => 0;

		internal static int ExtraResults(int crew)
		{
			return Mathf.Max(0, Players - crew);
		}

		internal static string Name(int slot)
		{
			return $"Employee #{slot}";
		}
	}
	[HarmonyPatch]
	internal static class ResultsGrid
	{
		private static readonly Vector2 AreaCentre = new Vector2(8f, 11f);

		private static readonly Vector2 AreaSize = new Vector2(402f, 210f);

		private const int Columns = 4;

		private const float CellGap = 4f;

		private const float Padding = 4f;

		private const float NameSize = 12f;

		private const float NoteSize = 9f;

		private static readonly Vector2 IconSize = new Vector2(24f, 14f);

		private static readonly Color Backing = new Color(0.27f, 0.02f, 0.02f, 1f);

		private const float BorderWidth = 1.5f;

		private const string GridName = "ExtraHeads Results";

		[HarmonyPatch(typeof(HUDManager), "FillEndGameStats")]
		[HarmonyPostfix]
		private static void FillGrid(HUDManager __instance, EndOfGameStats stats)
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Invalid comparison between Unknown and I4
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			EndOfGameStatUIElements statsUIElements = __instance.statsUIElements;
			object obj;
			if (statsUIElements.playerNamesText.Length == 0)
			{
				obj = null;
			}
			else
			{
				Transform parent = ((TMP_Text)statsUIElements.playerNamesText[0]).transform.parent;
				obj = ((parent != null) ? parent.parent : null);
			}
			Transform val = (Transform)obj;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			List<int> list = new List<int>();
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			for (int i = 0; i < allPlayerScripts.Length; i++)
			{
				if (allPlayerScripts[i].disconnectedMidGame || allPlayerScripts[i].isPlayerDead || allPlayerScripts[i].isPlayerControlled)
				{
					list.Add(i);
				}
			}
			bool flag = list.Count + Preview.ExtraResults(list.Count) > 4;
			for (int j = 0; j < statsUIElements.playerNamesText.Length; j++)
			{
				((Component)((TMP_Text)statsUIElements.playerNamesText[j]).transform.parent).gameObject.SetActive(!flag);
			}
			Transform val2 = val.Find("ExtraHeads Results");
			if ((Object)(object)val2 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
			if (!flag)
			{
				return;
			}
			RectTransform parent2 = Box(val, "ExtraHeads Results", AreaCentre, AreaSize, Backing);
			int num = list.Count + Preview.ExtraResults(list.Count);
			int num2 = Mathf.Max(1, Mathf.CeilToInt((float)num / 4f));
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor((AreaSize.x - 20f) / 4f, (AreaSize.y - 4f * (float)(num2 + 1)) / (float)num2);
			TextMeshProUGUI val4 = statsUIElements.playerNamesText[0];
			Vector2 centre = default(Vector2);
			for (int k = 0; k < num; k++)
			{
				int num3 = k % 4;
				int num4 = k / 4;
				((Vector2)(ref centre))..ctor((0f - AreaSize.x) / 2f + 4f + val3.x / 2f + (float)num3 * (val3.x + 4f), AreaSize.y / 2f - 4f - val3.y / 2f - (float)num4 * (val3.y + 4f));
				RectTransform frame = Box((Transform)(object)parent2, $"Cell {k}", centre, val3, Color.clear);
				Outline(frame, ((Graphic)val4).color);
				if (k < list.Count)
				{
					PlayerControllerB val5 = allPlayerScripts[list[k]];
					List<string> playerNotes = stats.allPlayerStats[list[k]].playerNotes;
					Sprite icon = ((!val5.isPlayerDead) ? statsUIElements.aliveIcon : (((int)val5.causeOfDeath == 10) ? statsUIElements.missingIcon : statsUIElements.deceasedIcon));
					Fill(frame, val3, val4, val5.playerUsername, icon, (playerNotes.Count > 0) ? playerNotes[0] : "");
				}
				else
				{
					Fill(frame, val3, val4, Preview.Name(k), (k % 3 == 0) ? statsUIElements.deceasedIcon : statsUIElements.aliveIcon, (k % 2 == 0) ? "Most paranoid employee" : "");
				}
			}
		}

		private static void Fill(RectTransform frame, Vector2 cell, TextMeshProUGUI style, string name, Sprite icon, string note)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			Text(frame, "Name", name, style, 12f, new Vector2(0f, cell.y / 2f - 4f - 6f), new Vector2(cell.x - 8f, 14f));
			Image component = ((Component)Box((Transform)(object)frame, "State", new Vector2(cell.x / 2f - 4f - IconSize.x / 2f, (0f - cell.y) / 2f + 4f + IconSize.y / 2f), IconSize, ((Graphic)style).color)).GetComponent<Image>();
			component.sprite = icon;
			component.preserveAspect = true;
			if (note.Length > 0)
			{
				float num = cell.x - IconSize.x - 12f;
				Text(frame, "Note", "* " + note, style, 9f, new Vector2((0f - cell.x) / 2f + 4f + num / 2f, (0f - cell.y) / 2f + 4f + 9f), new Vector2(num, 20f));
			}
		}

		private static RectTransform Box(Transform parent, string name, Vector2 centre, Vector2 size, Color color)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			}).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			component.pivot = val;
			Vector2 anchorMin = (component.anchorMax = val);
			component.anchorMin = anchorMin;
			component.anchoredPosition = centre;
			component.sizeDelta = size;
			((Graphic)((Component)component).GetComponent<Image>()).color = color;
			return component;
		}

		private static void Outline(RectTransform frame, Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			Vector2 sizeDelta = frame.sizeDelta;
			Box((Transform)(object)frame, "Top", new Vector2(0f, sizeDelta.y / 2f), new Vector2(sizeDelta.x, 1.5f), color);
			Box((Transform)(object)frame, "Bottom", new Vector2(0f, (0f - sizeDelta.y) / 2f), new Vector2(sizeDelta.x, 1.5f), color);
			Box((Transform)(object)frame, "Left", new Vector2((0f - sizeDelta.x) / 2f, 0f), new Vector2(1.5f, sizeDelta.y), color);
			Box((Transform)(object)frame, "Right", new Vector2(sizeDelta.x / 2f, 0f), new Vector2(1.5f, sizeDelta.y), color);
		}

		private static void Text(RectTransform parent, string name, string text, TextMeshProUGUI style, float size, Vector2 centre, Vector2 box)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI obj = new GameObject(name, new Type[1] { typeof(RectTransform) }).AddComponent<TextMeshProUGUI>();
			RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
			((Transform)rectTransform).SetParent((Transform)(object)parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			rectTransform.pivot = val;
			Vector2 anchorMin = (rectTransform.anchorMax = val);
			rectTransform.anchorMin = anchorMin;
			rectTransform.anchoredPosition = centre;
			rectTransform.sizeDelta = box;
			((TMP_Text)obj).font = ((TMP_Text)style).font;
			((TMP_Text)obj).fontSharedMaterial = ((TMP_Text)style).fontSharedMaterial;
			((Graphic)obj).color = ((Graphic)style).color;
			((TMP_Text)obj).fontSize = size;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)257;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
			((TMP_Text)obj).text = text;
		}
	}
	[HarmonyPatch]
	internal static class SpectatorList
	{
		private const float RowSpacing = 70f;

		private const float FirstX = -64f;

		private const float FirstY = 0f;

		private const int RowsPerColumn = 5;

		private const float ColumnSpacing = 170f;

		private static readonly Dictionary<int, RectTransform> previewBoxes = new Dictionary<int, RectTransform>();

		[HarmonyPatch(typeof(HUDManager), "UpdateBoxesSpectateUI")]
		[HarmonyPostfix]
		private static void WrapIntoColumns(HUDManager __instance, Dictionary<Animator, PlayerControllerB> ___spectatingPlayerBoxes)
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (LobbySize.Expanded)
			{
				List<RectTransform> list = (from box in (from pair in ___spectatingPlayerBoxes
						where (Object)(object)pair.Key != (Object)null && ((Component)pair.Key).gameObject.activeSelf
						select ((int, RectTransform))((int)pair.Value.playerClientId, (RectTransform)((Component)pair.Key).transform)).Concat<(int, RectTransform)>(PreviewBoxes(__instance))
					orderby box.Item1
					select box.Item2).ToList();
				for (int num = 0; num < list.Count; num++)
				{
					int num2 = num / 5;
					int num3 = num % 5;
					list[num].anchoredPosition = new Vector2(-64f + (float)num2 * 170f, 0f - (float)num3 * 70f);
				}
			}
		}

		private static IEnumerable<(int, RectTransform)> PreviewBoxes(HUDManager hud)
		{
			PlayerControllerB[] players = StartOfRound.Instance.allPlayerScripts;
			for (int slot = 0; slot < Preview.Players && slot < players.Length; slot++)
			{
				if (!players[slot].isPlayerControlled && !players[slot].isPlayerDead)
				{
					if (!previewBoxes.TryGetValue(slot, out RectTransform value) || (Object)(object)value == (Object)null)
					{
						GameObject val = Object.Instantiate<GameObject>(hud.spectatingPlayerBoxPrefab, hud.SpectateBoxesContainer, false);
						val.SetActive(true);
						((TMP_Text)val.GetComponentInChildren<TextMeshProUGUI>()).text = Preview.Name(slot);
						Dictionary<int, RectTransform> dictionary = previewBoxes;
						int key = slot;
						RectTransform val2 = (RectTransform)val.transform;
						value = val2;
						dictionary[key] = val2;
					}
					yield return (slot, value);
				}
			}
		}
	}
}
namespace ExtraHeads.Cosmetics
{
	internal static class CosmeticLibrary
	{
		internal sealed class Piece
		{
			public string Role = "";

			public Vector3 Pivot;

			public Vector3 Axis;

			public Mesh Mesh;

			public int[] MaterialIds;
		}

		internal sealed class Cosmetic
		{
			public string Id = "";

			public string Name = "";

			public string Spot = "";

			public string Bone = "";

			public string Motion = "";

			public Vector3 Base;

			public Vector3 Up;

			public Vector3 Forward;

			public List<Piece> Pieces = new List<Piece>();

			public Sprite? Icon;
		}

		private struct MaterialSpec
		{
			public string Name;

			public Color Colour;

			public float Emit;

			public float Rough;

			public float Metal;

			public float Alpha;
		}

		private const float EmissionScale = 40f;

		internal static readonly List<Cosmetic> All = new List<Cosmetic>();

		internal static readonly Dictionary<string, Cosmetic> ById = new Dictionary<string, Cosmetic>();

		private static readonly List<MaterialSpec> specs = new List<MaterialSpec>();

		private static Material[]? materials;

		internal static bool Loaded { get; private set; }

		private static string Folder => Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "Assets");

		internal static void Load()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			if (Loaded)
			{
				return;
			}
			Loaded = true;
			string text = Path.Combine(Folder, "cosmetics.bin");
			if (!File.Exists(text))
			{
				Plugin.Logger.LogWarning((object)("No cosmetics file at " + text + "; cosmetics are off."));
				return;
			}
			try
			{
				using GZipStream input = new GZipStream(File.OpenRead(text), CompressionMode.Decompress);
				using BinaryReader binaryReader = new BinaryReader(input);
				if (new string(binaryReader.ReadChars(4)) != "EHC2")
				{
					Plugin.Logger.LogWarning((object)"Cosmetics file is from another version; cosmetics are off.");
					return;
				}
				int num = binaryReader.ReadInt32();
				for (int i = 0; i < num; i++)
				{
					specs.Add(new MaterialSpec
					{
						Name = binaryReader.ReadString(),
						Colour = new Color(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()),
						Emit = binaryReader.ReadSingle(),
						Rough = binaryReader.ReadSingle(),
						Metal = binaryReader.ReadSingle(),
						Alpha = binaryReader.ReadSingle()
					});
				}
				int num2 = binaryReader.ReadInt32();
				for (int j = 0; j < num2; j++)
				{
					Cosmetic cosmetic = new Cosmetic
					{
						Id = binaryReader.ReadString(),
						Name = binaryReader.ReadString(),
						Spot = binaryReader.ReadString(),
						Bone = binaryReader.ReadString(),
						Motion = binaryReader.ReadString(),
						Base = ReadVector(binaryReader),
						Up = ReadVector(binaryReader),
						Forward = ReadVector(binaryReader)
					};
					int num3 = binaryReader.ReadInt32();
					for (int k = 0; k < num3; k++)
					{
						cosmetic.Pieces.Add(ReadPiece(binaryReader, cosmetic.Id));
					}
					cosmetic.Icon = LoadIcon(cosmetic.Id);
					All.Add(cosmetic);
					ById[cosmetic.Id] = cosmetic;
				}
				Plugin.Logger.LogInfo((object)$"Loaded {All.Count} cosmetics.");
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Couldn't read the cosmetics file; cosmetics are off. {arg}");
				All.Clear();
				ById.Clear();
			}
		}

		private static Piece ReadPiece(BinaryReader r, string id)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			Piece piece = new Piece
			{
				Role = r.ReadString(),
				Pivot = ReadVector(r),
				Axis = ReadVector(r)
			};
			int num = r.ReadInt32();
			Vector3[] array = (Vector3[])(object)new Vector3[num];
			Vector3[] array2 = (Vector3[])(object)new Vector3[num];
			for (int i = 0; i < num; i++)
			{
				array[i] = ReadVector(r) - piece.Pivot;
				array2[i] = ReadVector(r);
			}
			int num2 = r.ReadInt32();
			Mesh val = new Mesh
			{
				name = "ExtraHeads " + id + " " + piece.Role
			};
			val.indexFormat = (IndexFormat)(num > 65000);
			val.vertices = array;
			val.normals = array2;
			val.subMeshCount = num2;
			piece.MaterialIds = new int[num2];
			for (int j = 0; j < num2; j++)
			{
				piece.MaterialIds[j] = r.ReadInt32();
				int[] array3 = new int[r.ReadInt32()];
				for (int k = 0; k < array3.Length; k++)
				{
					array3[k] = r.ReadInt32();
				}
				val.SetTriangles(array3, j);
			}
			val.RecalculateBounds();
			val.UploadMeshData(true);
			piece.Mesh = val;
			return piece;
		}

		private static Vector3 ReadVector(BinaryReader r)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle());
		}

		private static Sprite? LoadIcon(string id)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			string path = Path.Combine(Folder, "icons", id + ".png");
			if (!File.Exists(path))
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
			{
				name = "ExtraHeads icon " + id
			};
			if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path), true))
			{
				return null;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}

		internal static Material[] Materials(Material source)
		{
			if (materials != null)
			{
				return materials;
			}
			materials = (Material[]?)(object)new Material[specs.Count];
			for (int i = 0; i < specs.Count; i++)
			{
				materials[i] = MakeMaterial(source, specs[i]);
			}
			Plugin.Logger.LogInfo((object)("Cosmetic materials made from '" + ((Object)source).name + "' (" + ((Object)source.shader).name + ")."));
			return materials;
		}

		private static Material MakeMaterial(Material source, MaterialSpec spec)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: 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)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			Material val = new Material(source)
			{
				name = "ExtraHeads " + spec.Name
			};
			string[] array = new string[6] { "_BaseColorMap", "_MainTex", "_MaskMap", "_NormalMap", "_EmissiveColorMap", "_DetailMap" };
			foreach (string text in array)
			{
				if (val.HasProperty(text))
				{
					val.SetTexture(text, (Texture)null);
				}
			}
			array = new string[5] { "_MASKMAP", "_NORMALMAP", "_NORMALMAP_TANGENT_SPACE", "_EMISSIVE_COLOR_MAP", "_DETAIL_MAP" };
			foreach (string text2 in array)
			{
				val.DisableKeyword(text2);
			}
			Color colour = spec.Colour;
			float value = 1f - spec.Rough;
			float value2 = spec.Metal;
			if (spec.Alpha < 0.5f)
			{
				((Color)(ref colour))..ctor(0.08f, 0.1f, 0.12f);
				value = 0.95f;
				value2 = 0.6f;
			}
			Set(val, "_BaseColor", ((Color)(ref colour)).gamma);
			Set(val, "_Color", ((Color)(ref colour)).gamma);
			Set(val, "_Metallic", value2);
			Set(val, "_Smoothness", value);
			Set(val, "_SmoothnessRemapMax", value);
			Set(val, "_SmoothnessRemapMin", 0f);
			Set(val, "_MetallicRemapMax", value2);
			Set(val, "_MetallicRemapMin", 0f);
			Color value3;
			if (!(spec.Emit > 0f))
			{
				value3 = Color.bla