Decompiled source of MoreCrackTogether v0.6.2

CrackLargerLobbies.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrackLargerLobbies.Config;
using CrackLargerLobbies.Patches;
using Dissonance;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
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("CrackLargerLobbies")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Raises CRACK's 4-player lobby cap (configurable, default 8). Extra players share quarters rooms. Every player installs it.")]
[assembly: AssemblyFileVersion("0.6.2.0")]
[assembly: AssemblyInformationalVersion("0.6.2")]
[assembly: AssemblyProduct("CrackLargerLobbies")]
[assembly: AssemblyTitle("CrackLargerLobbies")]
[assembly: AssemblyVersion("0.6.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 CrackLargerLobbies
{
	public static class Diagnostics
	{
		private static readonly HashSet<string> _failed = new HashSet<string>();

		public static void Safe(string what, Action a)
		{
			try
			{
				a();
			}
			catch (Exception ex)
			{
				if (_failed.Add(what))
				{
					Plugin.Log.LogWarning((object)("[LL] probe '" + what + "' failed (logged once): " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		public static bool SafeBool(string what, Func<bool> a)
		{
			try
			{
				return a();
			}
			catch (Exception ex)
			{
				if (_failed.Add(what))
				{
					Plugin.Log.LogWarning((object)("[LL] probe '" + what + "' failed (logged once): " + ex.GetType().Name + ": " + ex.Message));
				}
				return true;
			}
		}

		private static object F(object o, string field)
		{
			return Traverse.Create(o).Field(field).GetValue();
		}

		public static void LogScene(Scene scene)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)$"[LL] scene '{((Scene)(ref scene)).name}' loaded. IsModded={ModDetection.IsModded} Blocked={ModDetection.Blocked}");
			QuartersRoom[] array = Object.FindObjectsByType<QuartersRoom>((FindObjectsSortMode)0);
			Bed[] array2 = Object.FindObjectsByType<Bed>((FindObjectsSortMode)0);
			Wardrobe[] array3 = Object.FindObjectsByType<Wardrobe>((FindObjectsSortMode)0);
			QuartersDoor[] array4 = Object.FindObjectsByType<QuartersDoor>((FindObjectsSortMode)0);
			Plugin.Log.LogInfo((object)$"[LL] inventory rooms={array.Length} beds={array2.Length} wardrobes={array3.Length} doors={array4.Length}");
			QuartersRoom[] array5 = array;
			foreach (QuartersRoom val in array5)
			{
				Plugin.Log.LogInfo((object)string.Format("[LL] room '{0}' idx={1} door={2} spawn={3}", ((Object)val).name, val.PlayerIndex, F(val, "_door") != null, ((Object)(object)val.SpawnPoint != (Object)null) ? ((object)val.SpawnPoint.position/*cast due to .constrained prefix*/).ToString() : "null"));
			}
			Bed[] array6 = array2;
			foreach (Bed val2 in array6)
			{
				Plugin.Log.LogInfo((object)string.Format("[LL] bed '{0}' idx={1} sceneId={2}", ((Object)val2).name, F(val2, "_playerIndex"), SceneId((Component)(object)val2)));
			}
			Wardrobe[] array7 = array3;
			foreach (Wardrobe val3 in array7)
			{
				Plugin.Log.LogInfo((object)string.Format("[LL] wardrobe '{0}' idx={1} sceneId={2}", ((Object)val3).name, F(val3, "_playerIndex"), SceneId((Component)(object)val3)));
			}
			QuartersDoor[] array8 = array4;
			foreach (QuartersDoor val4 in array8)
			{
				Plugin.Log.LogInfo((object)string.Format("[LL] door '{0}' idx={1} sceneId={2}", ((Object)val4).name, F(val4, "_assignedPlayerIndex"), SceneId((Component)(object)val4)));
			}
		}

		private static string SceneId(Component c)
		{
			NetworkIdentity val = c.GetComponent<NetworkIdentity>() ?? c.GetComponentInParent<NetworkIdentity>();
			if (!((Object)(object)val != (Object)null))
			{
				return "none";
			}
			return val.sceneId.ToString("X");
		}

		public static void LogPeer()
		{
			if (!NetworkClient.active && !NetworkServer.active)
			{
				return;
			}
			GameManager instance = GameManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			List<string> list = new List<string>();
			foreach (PlayerController player in instance.players)
			{
				list.Add(((Object)(object)player != (Object)null) ? player.index.ToString() : "null");
			}
			Plugin.Log.LogInfo((object)string.Format("[LL] peer server={0} client={1} players={2} idx=[{3}] NS.max={4} conns={5}", NetworkServer.active, NetworkClient.active, instance.players.Count, string.Join(",", list), NetworkServer.maxConnections, NetworkServer.connections.Count));
			DissonanceComms val = Object.FindFirstObjectByType<DissonanceComms>();
			if ((Object)(object)val != (Object)null)
			{
				Plugin.Log.LogInfo((object)$"[LL] dissonance players={val.Players.Count}");
			}
		}
	}
	[HarmonyPatch(typeof(MyNetworkManager), "Awake")]
	internal static class P_NM_Awake
	{
		private static void Postfix(MyNetworkManager __instance)
		{
			Diagnostics.Safe("NM.Awake", delegate
			{
				Plugin.Log.LogInfo((object)$"[LL] NM.maxConnections={((NetworkManager)__instance).maxConnections} auth={((object)((NetworkManager)__instance).authenticator)?.GetType().Name} transport={((object)((NetworkManager)__instance).transport)?.GetType().Name}");
			});
		}
	}
	[HarmonyPatch(typeof(NetworkManager), "StartHost")]
	internal static class P_NM_StartHost
	{
		private static void Postfix()
		{
			Diagnostics.Safe("StartHost", delegate
			{
				object obj = (((Object)(object)Transport.active != (Object)null) ? Traverse.Create((object)Transport.active).Field("UseNextGenSteamNetworking").GetValue() : null);
				object obj2 = null;
				if ((Object)(object)Transport.active != (Object)null)
				{
					object value = Traverse.Create((object)Transport.active).Field("server").GetValue();
					if (value != null)
					{
						obj2 = Traverse.Create(value).Field("maxConnections").GetValue();
					}
				}
				Plugin.Log.LogInfo((object)$"[LL] StartHost NS.max={NetworkServer.maxConnections} nextGen={obj} fizzyMax={obj2} aoi={(Object)(object)NetworkServer.aoi != (Object)null} transport={((object)Transport.active)?.GetType().FullName}");
			});
		}
	}
	[HarmonyPatch(typeof(MyNetworkManager), "OnServerSceneChanged")]
	internal static class P_NM_SceneChanged
	{
		private static void Postfix(string sceneName)
		{
			Diagnostics.Safe("OnServerSceneChanged", delegate
			{
				Plugin.Log.LogInfo((object)$"[LL] sceneChanged '{sceneName}' NS.max={NetworkServer.maxConnections}");
			});
		}
	}
	[HarmonyPatch(typeof(MyNetworkManager), "SpawnPlayerAndSync")]
	internal static class P_NM_SpawnGate
	{
		private static void Prefix(MyNetworkManager __instance, NetworkConnectionToClient conn)
		{
			Diagnostics.Safe("SpawnGate", delegate
			{
				ICollection<int> collection = Traverse.Create((object)__instance).Field("_spawnPending").GetValue() as ICollection<int>;
				GameManager instance = GameManager.instance;
				Plugin.Log.LogInfo((object)$"[LL] gate conn={conn?.connectionId} players={instance?.players.Count} pending={collection?.Count} freeIdx={((instance != null) ? new int?(instance.GetAvailablePlayerIndex()) : ((int?)null))} max={((NetworkManager)__instance).maxConnections}");
			});
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "UpdateLobbyMemberLimit")]
	internal static class P_Lobby_Limit
	{
		private static int _lastLogged = int.MinValue;

		private static void Postfix(SteamLobby __instance)
		{
			Diagnostics.Safe("LobbyLimit", delegate
			{
				//IL_0022: 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_0032: 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)
				if (NetworkServer.active)
				{
					CSteamID val = (CSteamID)Traverse.Create((object)__instance).Field("currentLobbyID").GetValue();
					if (((CSteamID)(ref val)).IsValid())
					{
						int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val);
						if (lobbyMemberLimit != _lastLogged)
						{
							_lastLogged = lobbyMemberLimit;
							Plugin.Log.LogInfo((object)$"[LL] lobbyLimit={lobbyMemberLimit} members={SteamMatchmaking.GetNumLobbyMembers(val)} conns={NetworkServer.connections.Count}");
						}
					}
				}
			});
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "Awake")]
	internal static class P_Lobby_Awake
	{
		private static void Postfix(SteamLobby __instance)
		{
			Diagnostics.Safe("LobbyAwake", delegate
			{
				Plugin.Log.LogInfo((object)string.Format("[LL] lobby grace={0} roomCheck={1}", Traverse.Create((object)__instance).Field("_connectingGrace").GetValue(), Traverse.Create((object)__instance).Field("_roomCheckInterval").GetValue()));
			});
		}
	}
	[HarmonyPatch(typeof(VersionAuthenticator), "OnStartServer")]
	internal static class P_Auth_Start
	{
		private static void Postfix(VersionAuthenticator __instance)
		{
			Diagnostics.Safe("AuthStart", delegate
			{
				Plugin.Log.LogInfo((object)string.Format("[LL] auth rejectDelay={0} IsModded={1}", Traverse.Create((object)__instance).Field("_rejectDelay").GetValue(), ModDetection.IsModded));
			});
		}
	}
	[HarmonyPatch(typeof(GameManager), "GetSpawnPoint")]
	internal static class P_GM_Spawn
	{
		private static void Postfix(int playerIndex, (Vector3, Quaternion) __result)
		{
			Diagnostics.Safe("GetSpawnPoint", delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				if (__result.Item1 == Vector3.zero)
				{
					Plugin.Log.LogWarning((object)$"[LL] origin spawn idx={playerIndex} t={Time.time}");
				}
				else
				{
					Plugin.Log.LogInfo((object)$"[LL] spawn idx={playerIndex} pos={__result.Item1}");
				}
			});
		}
	}
	[HarmonyPatch(typeof(GameManager), "AddPlayer")]
	internal static class P_GM_AddPlayer
	{
		private static void Postfix(GameManager __instance, PlayerController playerController)
		{
			Diagnostics.Safe("AddPlayer", delegate
			{
				Plugin.Log.LogInfo((object)$"[LL] addPlayer idx={playerController?.index} count={__instance.players.Count} server={NetworkServer.active}");
			});
		}
	}
	[HarmonyPatch(typeof(KillBox), "RecoverPlayer")]
	internal static class P_KillBox
	{
		private static void Prefix(Player player)
		{
			Diagnostics.Safe("RecoverPlayer", delegate
			{
				Plugin.Log.LogInfo((object)$"[LL] killbox recover idx={player?.playerController?.index} t={Time.time}");
			});
		}
	}
	[HarmonyPatch(typeof(ShiftSummaryManager), "ServerBuildSummary")]
	internal static class P_Summary
	{
		private static void Postfix(ShiftSummaryManager __instance)
		{
			Diagnostics.Safe("Summary", delegate
			{
				string s = (Traverse.Create((object)__instance).Field("_summaryJson").GetValue() as string) ?? "";
				Plugin.Log.LogInfo((object)$"[LL] summaryJson bytes={Encoding.UTF8.GetByteCount(s)} crew={GameManager.PlayerCount} (Mirror string limit 65534)");
			});
		}
	}
	[HarmonyPatch(typeof(BreakManager), "CalculateSleepLocationFees")]
	internal static class P_SleepFees
	{
		private static void Postfix(BreakManager __instance, object __result)
		{
			Diagnostics.Safe("SleepFees", delegate
			{
				int num = ((__result is ICollection collection) ? collection.Count : (-1));
				Plugin.Log.LogInfo((object)$"[LL] sleepFees count={num} allAsleep={__instance.AllPlayersAsleep} crew={GameManager.PlayerCount}");
			});
		}
	}
	[HarmonyPatch(typeof(BreakManager), "StartWork")]
	internal static class P_StartWork
	{
		private static void Prefix()
		{
			Diagnostics.Safe("StartWork", delegate
			{
				MethodBase methodBase = new StackTrace().GetFrame(3)?.GetMethod();
				Plugin.Log.LogInfo((object)("[LL] StartWork from " + methodBase?.DeclaringType?.Name + "." + methodBase?.Name));
			});
		}
	}
	[BepInPlugin("Haaylo.CrackLargerLobbies", "CrackLargerLobbies", "0.6.2")]
	public class Plugin : BaseUnityPlugin
	{
		private static readonly HashSet<string> _faulted = new HashSet<string>();

		private Harmony _harmony;

		private float _nextPeerLog;

		private float _menuSeenAt = -1f;

		private bool _autoHosted;

		private bool _selfTested;

		private bool _menuProbed;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static int FaultCount => _faulted.Count;

		public static void Fault(string site, Exception e)
		{
			if (_faulted.Add(site))
			{
				Log.LogError((object)$"[LL] patch '{site}' failed (vanilla behaviour from now on): {e}");
			}
		}

		private void Awake()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				ModConfig.Bind(((BaseUnityPlugin)this).Config);
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Config binding failed; defaults in effect: {arg}");
			}
			try
			{
				_harmony = new Harmony("Haaylo.CrackLargerLobbies");
				_harmony.PatchAll(typeof(Plugin).Assembly);
				int num = 0;
				foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods())
				{
					_ = patchedMethod;
					num++;
				}
				Log.LogInfo((object)string.Format("{0} {1}: {2} game methods patched.", "CrackLargerLobbies", "0.6.2", num));
			}
			catch (Exception arg2)
			{
				Log.LogError((object)$"Harmony patching failed; the mod stays idle: {arg2}");
			}
			Log.LogInfo((object)$"[LL] cap={ModConfig.CapValue} shareAllRooms={ModConfig.ShareAllRooms?.Value} scaleEvents={ModConfig.ScaleEvents?.Value} extendColors={ModConfig.ExtendColors?.Value} unity={Application.unityVersion} appVersion={Application.version}");
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Rooms.Invalidate();
				Apply.Cap("sceneLoaded:" + ((Scene)(ref scene)).name);
			}
			catch (Exception e)
			{
				Fault("sceneLoaded", e);
			}
			if (ModConfig.DiagnosticsEnabled != null && ModConfig.DiagnosticsEnabled.Value)
			{
				Diagnostics.Safe("sceneLoaded", delegate
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					Diagnostics.LogScene(scene);
				});
			}
			if (!NetworkServer.active && !NetworkClient.active)
			{
				_menuSeenAt = Time.unscaledTime;
			}
			if (ModConfig.SelfTest != null && ModConfig.SelfTest.Value && !_selfTested && NetworkServer.active)
			{
				_selfTested = true;
				((MonoBehaviour)this).StartCoroutine(SelfTestAfterSettle());
			}
		}

		private static bool SceneSettled()
		{
			try
			{
				return (Object)(object)GameManager.instance != (Object)null && GameManager.instance.players.Count > 0 && Rooms.Count > 0;
			}
			catch (Exception e)
			{
				Fault("selfTest.settle", e);
				return true;
			}
		}

		private IEnumerator SelfTestAfterSettle()
		{
			float deadline = Time.unscaledTime + 60f;
			while (Time.unscaledTime < deadline && !SceneSettled())
			{
				yield return (object)new WaitForSecondsRealtime(1f);
			}
			yield return (object)new WaitForSecondsRealtime(3f);
			yield return ((MonoBehaviour)this).StartCoroutine(SummaryProbe());
			Diagnostics.Safe("selfTest", delegate
			{
				SelfTest.Run(_harmony);
			});
			Diagnostics.Safe("summaryProbe.clear", delegate
			{
				if ((Object)(object)ShiftSummaryManager.instance != (Object)null)
				{
					ShiftSummaryManager.instance.ServerClearSummary();
				}
			});
			float num = ((ModConfig.SelfTestQuitSeconds != null) ? ModConfig.SelfTestQuitSeconds.Value : 0f);
			if (num > 0f)
			{
				yield return (object)new WaitForSecondsRealtime(num);
				Log.LogInfo((object)"[LL][SELFTEST] quitting");
				Application.Quit();
			}
		}

		private IEnumerator SummaryProbe()
		{
			bool flag = false;
			try
			{
				ShiftSummaryManager instance = ShiftSummaryManager.instance;
				if ((Object)(object)instance == (Object)null)
				{
					Log.LogWarning((object)"[LL][SELFTEST] shiftsummary: no ShiftSummaryManager");
				}
				else
				{
					int capValue = ModConfig.CapValue;
					string[] array = new string[capValue];
					for (int i = 0; i < capValue; i++)
					{
						array[i] = "TESTER " + (i + 1);
					}
					AccessTools.Field(typeof(ShiftSummaryManager), "SimNamesLong").SetValue(null, array);
					instance.ServerSimulate("busy");
					flag = true;
				}
			}
			catch (Exception e)
			{
				Fault("summaryProbe", e);
			}
			if (!flag)
			{
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(7f);
			try
			{
				ShiftCompleteUI val = Object.FindFirstObjectByType<ShiftCompleteUI>((FindObjectsInactive)1);
				if ((Object)(object)val != (Object)null)
				{
					SummaryScroll.ScrollTo(val, 1f);
				}
				Log.LogInfo((object)("[LL][SELFTEST] shiftsummary " + (((Object)(object)val != (Object)null) ? SummaryScroll.Describe(val) : "no ShiftCompleteUI") + " (top; shown for 7 s)"));
			}
			catch (Exception e2)
			{
				Fault("summaryProbe.describe", e2);
			}
			yield return (object)new WaitForSecondsRealtime(7f);
			try
			{
				ShiftCompleteUI val2 = Object.FindFirstObjectByType<ShiftCompleteUI>((FindObjectsInactive)1);
				float num = (((Object)(object)val2 != (Object)null) ? SummaryScroll.ScrollTo(val2, 0f) : (-1f));
				Log.LogInfo((object)$"[LL][SELFTEST] shiftsummary-scrolled normalized={num:F2} (shown for 7 s)");
			}
			catch (Exception e3)
			{
				Fault("summaryProbe.scroll", e3);
			}
			yield return (object)new WaitForSecondsRealtime(7f);
		}

		private IEnumerator MenuProbe()
		{
			string opened = "none";
			try
			{
				MainMenuController val = Object.FindFirstObjectByType<MainMenuController>();
				if ((Object)(object)val != (Object)null)
				{
					val.ShowHost();
					opened = "ShowHost";
				}
				else
				{
					Button[] array = Object.FindObjectsByType<Button>((FindObjectsSortMode)0);
					foreach (Button val2 in array)
					{
						TMP_Text componentInChildren = ((Component)val2).GetComponentInChildren<TMP_Text>(true);
						if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text != null && componentInChildren.text.IndexOf("HOST", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							((UnityEvent)val2.onClick).Invoke();
							opened = ((Object)val2).name;
							break;
						}
					}
				}
			}
			catch (Exception e)
			{
				Fault("menuProbe.open", e);
			}
			yield return (object)new WaitForSecondsRealtime(1f);
			HostPanelController val3 = Object.FindFirstObjectByType<HostPanelController>((FindObjectsInactive)1);
			if ((Object)(object)val3 == (Object)null)
			{
				Log.LogWarning((object)"[LL][SELFTEST] hostpanel: no HostPanelController in the menu scene");
				yield break;
			}
			GameObject val4 = null;
			try
			{
				val4 = HostPanelUi.Ensure(val3);
			}
			catch (Exception e2)
			{
				Fault("menuProbe", e2);
			}
			string text = (((Object)(object)val4 != (Object)null) ? HostPanelUi.CurrentLabel(val4) : null);
			Slider val5 = HostPanelUi.FindSlider(val4);
			Log.LogInfo((object)string.Format("[LL][SELFTEST] hostpanel row={0} label=\"{1}\" slider={2} opened={3} panelActive={4} (shown for 4 s)", ((Object)(object)val4 != (Object)null) ? "ok" : "missing", text, ((Object)(object)val5 != (Object)null) ? val5.value.ToString() : "none", opened, ((Component)val3).gameObject.activeInHierarchy));
			yield return (object)new WaitForSecondsRealtime(4f);
			try
			{
				MainMenuController val6 = Object.FindFirstObjectByType<MainMenuController>();
				if ((Object)(object)val6 != (Object)null)
				{
					val6.ShowSettings();
				}
			}
			catch (Exception e3)
			{
				Fault("menuProbe.settings", e3);
			}
			yield return (object)new WaitForSecondsRealtime(1f);
			try
			{
				SettingsPanel val7 = Object.FindFirstObjectByType<SettingsPanel>((FindObjectsInactive)1);
				GameObject val8 = (((Object)(object)val7 != (Object)null) ? SettingsUi.Ensure(val7) : null);
				List<string> values = SettingsUi.Verify(val8);
				Log.LogInfo((object)("[LL][SELFTEST] settings card=" + (((Object)(object)val8 != (Object)null) ? "ok" : "missing") + " problems=[" + string.Join("; ", values) + "] (panel shown for 4 s)"));
			}
			catch (Exception e4)
			{
				Fault("menuProbe.settingsCard", e4);
			}
			yield return (object)new WaitForSecondsRealtime(4f);
		}

		private void Update()
		{
			if (ModConfig.SelfTest != null && ModConfig.SelfTest.Value && !_menuProbed && _menuSeenAt >= 0f && Time.unscaledTime - _menuSeenAt > 3f && !NetworkServer.active && !NetworkClient.active)
			{
				_menuProbed = true;
				((MonoBehaviour)this).StartCoroutine(MenuProbe());
			}
			if (ModConfig.AutoHostOffline != null && ModConfig.AutoHostOffline.Value && !_autoHosted && Time.unscaledTime > 12f && (_menuSeenAt < 0f || Time.unscaledTime - _menuSeenAt > 10f) && !NetworkServer.active && !NetworkClient.active)
			{
				_autoHosted = Diagnostics.SafeBool("autoHost", AutoHostOffline);
			}
			if (ModConfig.DiagnosticsEnabled != null && ModConfig.DiagnosticsEnabled.Value && ModConfig.PeerIntervalSeconds != null && ModConfig.PeerIntervalSeconds.Value > 0f && Time.unscaledTime >= _nextPeerLog)
			{
				_nextPeerLog = Time.unscaledTime + ModConfig.PeerIntervalSeconds.Value;
				Diagnostics.Safe("peer", Diagnostics.LogPeer);
			}
		}

		private static bool AutoHostOffline()
		{
			if ((Object)(object)SteamLobby.instance == (Object)null || (Object)(object)NetworkManager.singleton == (Object)null)
			{
				return false;
			}
			int num = -1;
			for (int i = 0; i < 3; i++)
			{
				if (!SaveSlots.SlotExists(i))
				{
					num = i;
					break;
				}
			}
			if (num < 0)
			{
				Log.LogWarning((object)"[LL] autoHost: no empty save slot; not hosting (will not touch existing saves)");
				return true;
			}
			GameMode.Set((GameModeKind)0);
			SaveSlots.SelectedSlot = num;
			SaveSlots.StartNewGame = SaveSlots.PrepareSlot(num);
			SaveSlots.HandoffDone = true;
			Log.LogInfo((object)$"[LL] autoHost: offline session in empty slot {num}");
			SteamLobby.instance.HostOffline();
			return true;
		}
	}
	public static class PluginInfo
	{
		public const string GUID = "Haaylo.CrackLargerLobbies";

		public const string NAME = "CrackLargerLobbies";

		public const string VERSION = "0.6.2";
	}
	public static class RoomMath
	{
		public static bool NeedsMapping(int playerIndex, int roomCount)
		{
			if (roomCount > 0)
			{
				return playerIndex >= roomCount;
			}
			return false;
		}

		public static int RoomIndex(int playerIndex, int roomCount)
		{
			if (roomCount > 0 && playerIndex >= 0)
			{
				return playerIndex % roomCount;
			}
			return playerIndex;
		}

		public static int Occupant(int playerIndex, int roomCount)
		{
			if (roomCount > 0 && playerIndex >= 0)
			{
				return playerIndex / roomCount;
			}
			return 0;
		}

		public static void Offset(int occupant, float step, out float right, out float forward)
		{
			right = 0f;
			forward = 0f;
			if (occupant > 0 && !(step <= 0f))
			{
				int num = (occupant - 1) / 8 + 1;
				int num2 = (occupant - 1) % 8;
				float num3 = step * (float)num;
				switch (num2)
				{
				case 0:
					right = num3;
					break;
				case 1:
					right = 0f - num3;
					break;
				case 2:
					forward = num3;
					break;
				case 3:
					forward = 0f - num3;
					break;
				case 4:
					right = num3;
					forward = num3;
					break;
				case 5:
					right = 0f - num3;
					forward = num3;
					break;
				case 6:
					right = num3;
					forward = 0f - num3;
					break;
				default:
					right = 0f - num3;
					forward = 0f - num3;
					break;
				}
			}
		}

		public static int BedSlot(int playerIndex, int bedIndex)
		{
			if (playerIndex < 0 || playerIndex == bedIndex)
			{
				return 0;
			}
			if (bedIndex >= 0 && playerIndex >= bedIndex)
			{
				return playerIndex;
			}
			return playerIndex + 1;
		}

		public static int LowestFreeIndex(ICollection<int> used, int cap)
		{
			for (int i = 0; i < cap; i++)
			{
				if (!used.Contains(i))
				{
					return i;
				}
			}
			return -1;
		}

		public static int Extrapolate(int[] table, int crew)
		{
			if (table == null || table.Length == 0)
			{
				return 0;
			}
			int num = table.Length;
			if (crew <= num)
			{
				return table[Math.Max(0, crew - 1)];
			}
			int num2 = table[num - 1];
			int num3 = ((num >= 2) ? Math.Max(0, num2 - table[num - 2]) : Math.Max(0, num2 / Math.Max(1, num)));
			return num2 + num3 * (crew - num);
		}

		public static float ExtraHue(int k)
		{
			double num = 0.08 + 0.6180339887 * (double)k;
			return (float)(num - Math.Floor(num));
		}
	}
	public static class SelfTest
	{
		private static int _pass;

		private static int _fail;

		private static void Check(string name, bool ok, string detail)
		{
			if (ok)
			{
				_pass++;
				Plugin.Log.LogInfo((object)("[LL][SELFTEST] " + name + ": PASS " + detail));
			}
			else
			{
				_fail++;
				Plugin.Log.LogError((object)("[LL][SELFTEST] " + name + ": FAIL " + detail));
			}
		}

		private static void Guarded(string name, Action a)
		{
			try
			{
				a();
			}
			catch (Exception ex)
			{
				Check(name, ok: false, "threw " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		public static void Run(Harmony harmony)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			_pass = (_fail = 0);
			int cap = ModConfig.CapValue;
			int r = Rooms.Count;
			ManualLogSource log = Plugin.Log;
			object[] obj = new object[4]
			{
				cap,
				r,
				NetworkServer.active,
				null
			};
			Scene activeScene = SceneManager.GetActiveScene();
			obj[3] = ((Scene)(ref activeScene)).name;
			log.LogInfo((object)string.Format("[LL][SELFTEST] begin cap={0} rooms={1} server={2} scene={3}", obj));
			Guarded("patches", delegate
			{
				int num2 = 0;
				int num3 = 0;
				List<string> list = new List<string>();
				Type[] types = typeof(SelfTest).Assembly.GetTypes();
				for (int j = 0; j < types.Length; j++)
				{
					foreach (HarmonyPatch customAttribute in ((MemberInfo)types[j]).GetCustomAttributes<HarmonyPatch>(inherit: true))
					{
						if (!(((HarmonyAttribute)customAttribute).info.declaringType == null) && ((HarmonyAttribute)customAttribute).info.methodName != null)
						{
							num2++;
							MethodInfo methodInfo = AccessTools.Method(((HarmonyAttribute)customAttribute).info.declaringType, ((HarmonyAttribute)customAttribute).info.methodName, (Type[])null, (Type[])null);
							Patches val = ((methodInfo != null) ? Harmony.GetPatchInfo((MethodBase)methodInfo) : null);
							if (val != null && val.Owners.Contains("Haaylo.CrackLargerLobbies"))
							{
								num3++;
							}
							else
							{
								list.Add(((HarmonyAttribute)customAttribute).info.declaringType.Name + "." + ((HarmonyAttribute)customAttribute).info.methodName);
							}
						}
					}
				}
				Check("patches", list.Count == 0, $"{num3}/{num2} patch classes bound" + ((list.Count > 0) ? (" missing: " + string.Join(",", list)) : ""));
			});
			Guarded("cap.networkManager", delegate
			{
				NetworkManager singleton = NetworkManager.singleton;
				Check("cap.networkManager", (Object)(object)singleton != (Object)null && singleton.maxConnections == cap, $"maxConnections={singleton?.maxConnections}");
			});
			Guarded("cap.networkServer", delegate
			{
				Check("cap.networkServer", !NetworkServer.active || NetworkServer.maxConnections == cap, $"NetworkServer.maxConnections={NetworkServer.maxConnections} active={NetworkServer.active}");
			});
			Guarded("index.free", delegate
			{
				GameManager instance = GameManager.instance;
				int num2 = (((Object)(object)instance != (Object)null) ? instance.GetAvailablePlayerIndex() : (-2));
				int num3 = (((Object)(object)instance != (Object)null) ? instance.players.Count : (-1));
				Check("index.free", (Object)(object)instance != (Object)null && num2 >= 0 && num2 < cap, $"players={num3} nextFree={num2}");
			});
			Guarded("rooms.count", delegate
			{
				Check("rooms.count", r > 0, $"R={r} (0 means the play scene is not loaded or _all is empty)");
			});
			if (r > 0)
			{
				GameManager gm = GameManager.instance;
				for (int num = r; num < cap; num++)
				{
					int i = num;
					Guarded($"spawn[{i}]", delegate
					{
						//IL_0039: Unknown result type (might be due to invalid IL or missing references)
						//IL_003e: 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_008d: Unknown result type (might be due to invalid IL or missing references)
						//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
						(Vector3, Quaternion) spawnPoint = gm.GetSpawnPoint(i);
						QuartersRoom val = QuartersRoom.Get(RoomMath.RoomIndex(i, r));
						bool flag = spawnPoint.Item1 != Vector3.zero;
						float num2 = -1f;
						if ((Object)(object)val != (Object)null && (Object)(object)val.SpawnPoint != (Object)null)
						{
							num2 = Vector3.Distance(spawnPoint.Item1, Rooms.OffsetPosition(val.SpawnPoint, RoomMath.Occupant(i, r)));
						}
						bool flag2 = num2 >= 0f && num2 < 0.05f;
						Check($"spawn[{i}]", flag && flag2, $"pos={spawnPoint.Item1} room={((val != null) ? new int?(val.PlayerIndex) : ((int?)null))} distToExpected={num2:F3}");
					});
					Guarded($"bed[{i}]", delegate
					{
						Bed forPlayer = Bed.GetForPlayer(i);
						Bed forPlayer2 = Bed.GetForPlayer(RoomMath.RoomIndex(i, r));
						Check($"bed[{i}]", (Object)(object)forPlayer != (Object)null && (Object)(object)forPlayer == (Object)(object)forPlayer2, "bed=" + (((Object)(object)forPlayer != (Object)null) ? ((Object)forPlayer).name : "null") + " sharedWith=" + (((Object)(object)forPlayer2 != (Object)null) ? ((Object)forPlayer2).name : "null"));
					});
				}
				Guarded("doors", delegate
				{
					QuartersDoor[] array = Object.FindObjectsByType<QuartersDoor>((FindObjectsSortMode)0);
					FieldRef<QuartersDoor, int> val = AccessTools.FieldRefAccess<QuartersDoor, int>("_assignedPlayerIndex");
					int num2 = 0;
					int num3 = 0;
					QuartersDoor[] array2 = array;
					foreach (QuartersDoor val2 in array2)
					{
						int num4 = val.Invoke(val2);
						if (num4 >= 0)
						{
							num3++;
							bool num5 = Owner.Shares(num4 + r, num4);
							int playerIndex = ((num4 + r + 1 < cap) ? (num4 + r + 1) : ((num4 + 1) % r));
							bool flag = (Rooms.ShareAll ? Owner.Shares(playerIndex, num4) : (!Owner.Shares(playerIndex, num4) || r == 1));
							if (num5 && flag)
							{
								num2++;
							}
						}
					}
					Check("doors", num3 > 0 && num2 == num3, string.Format("{0}/{1} doors accept their sharer and {2}", num2, num3, Rooms.ShareAll ? "everyone else (ShareAllRooms)" : "reject others"));
				});
				Guarded("wardrobe.restore", delegate
				{
					Wardrobe[] array = Object.FindObjectsByType<Wardrobe>((FindObjectsSortMode)0);
					int num2 = 0;
					Wardrobe[] array2 = array;
					foreach (Wardrobe val in array2)
					{
						int num3 = WardrobeFields.PlayerIndex.Invoke(val);
						int num4 = WardrobeFields.SwapFor(val, null);
						WardrobeFields.Restore(val, num4);
						if (num4 == int.MinValue && WardrobeFields.PlayerIndex.Invoke(val) == num3)
						{
							num2++;
						}
					}
					Check("wardrobe.restore", array.Length != 0 && num2 == array.Length, $"{num2}/{array.Length} wardrobes unchanged by a no-op swap");
				});
			}
			Guarded("scale.candy", delegate
			{
				CandyDropEvent val = Object.FindFirstObjectByType<CandyDropEvent>((FindObjectsInactive)1);
				if ((Object)(object)val == (Object)null)
				{
					Check("scale.candy", ok: true, "no CandyDropEvent in scene (skipped)");
				}
				else
				{
					MethodInfo methodInfo = AccessTools.Method(typeof(CandyDropEvent), "CountForCrew", (Type[])null, (Type[])null);
					int num2 = (int)methodInfo.Invoke(val, new object[1] { 4 });
					int num3 = (int)methodInfo.Invoke(val, new object[1] { cap });
					Check("scale.candy", cap <= 4 || num3 >= num2, $"crew4={num2} crew{cap}={num3}");
				}
			});
			Guarded("colors.blips", delegate
			{
				//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_006a: 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_007e: 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_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				PlayerBlips val = Object.FindFirstObjectByType<PlayerBlips>((FindObjectsInactive)1);
				if ((Object)(object)val == (Object)null)
				{
					Check("colors.blips", ok: true, "no PlayerBlips in scene (skipped)");
				}
				else
				{
					MethodInfo methodInfo = AccessTools.Method(typeof(PlayerBlips), "ColorForIndex", (Type[])null, (Type[])null);
					Color val2 = (Color)methodInfo.Invoke(val, new object[1] { 0 });
					Color val3 = (Color)methodInfo.Invoke(val, new object[1] { 4 });
					Check("colors.blips", cap <= 4 || val2 != val3, $"c0={val2} c4={val3}");
				}
			});
			Guarded("colors.palette", delegate
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: 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_0025: 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)
				Color[] array = Palette.Extend((Color[])(object)new Color[4]
				{
					Color.red,
					Color.blue,
					Color.green,
					Color.yellow
				}, cap);
				HashSet<Color> hashSet = new HashSet<Color>(array);
				Check("colors.palette", array.Length == Math.Max(4, cap) && hashSet.Count == array.Length, $"{array.Length} colours, {hashSet.Count} distinct");
			});
			Guarded("hostpanel.row", delegate
			{
				HostPanelController val = Object.FindFirstObjectByType<HostPanelController>((FindObjectsInactive)1);
				if ((Object)(object)val == (Object)null)
				{
					Check("hostpanel.row", ok: true, "no HostPanelController in this scene (skipped)");
				}
				else
				{
					GameObject val2 = HostPanelUi.Ensure(val);
					string text = (((Object)(object)val2 != (Object)null) ? HostPanelUi.CurrentLabel(val2) : null);
					Slider val3 = HostPanelUi.FindSlider(val2);
					bool flag = (((Object)(object)Object.FindFirstObjectByType<SettingsPanel>((FindObjectsInactive)1) == (Object)null) ? ((Object)(object)val3 == (Object)null) : ((Object)(object)val3 != (Object)null && (int)val3.value == cap && val3.minValue == 4f && val3.maxValue == 16f && val3.wholeNumbers));
					bool ok = (Object)(object)val2 != (Object)null && text == HostPanelUi.Label(cap) && flag;
					Check("hostpanel.row", ok, "label=\"" + text + "\" slider=" + (((Object)(object)val3 != (Object)null) ? $"{val3.value} [{val3.minValue}-{val3.maxValue}] whole={val3.wholeNumbers}" : "null"));
				}
			});
			Guarded("settings.card", delegate
			{
				SettingsPanel val = Object.FindFirstObjectByType<SettingsPanel>((FindObjectsInactive)1);
				if ((Object)(object)val == (Object)null)
				{
					Check("settings.card", ok: true, "no SettingsPanel in this scene (skipped)");
				}
				else
				{
					List<string> list = SettingsUi.Verify(SettingsUi.Ensure(val));
					Check("settings.card", list.Count == 0, (list.Count == 0) ? "3 tweak toggles match config" : string.Join("; ", list));
				}
			});
			Guarded("summary.scroll", delegate
			{
				ShiftCompleteUI val = Object.FindFirstObjectByType<ShiftCompleteUI>((FindObjectsInactive)1);
				if ((Object)(object)val == (Object)null)
				{
					Check("summary.scroll", ok: true, "no ShiftCompleteUI in this scene (skipped)");
				}
				else
				{
					string text = SummaryScroll.Describe(val);
					bool flag = text.Contains($"rows={cap} ");
					bool flag2 = text.Contains("scroll=True");
					Check("summary.scroll", flag && flag2, text);
				}
			});
			Check("patchFaults", Plugin.FaultCount == 0, $"{Plugin.FaultCount} patch sites faulted (see [LL] patch '...' failed lines)");
			Plugin.Log.LogInfo((object)$"[LL][SELFTEST] summary: {_pass} passed, {_fail} failed");
		}
	}
}
namespace CrackLargerLobbies.Patches
{
	[HarmonyPatch(typeof(MyNetworkManager), "Awake")]
	internal static class P_Cap_Awake
	{
		private static void Postfix(MyNetworkManager __instance)
		{
			try
			{
				int maxConnections = ((NetworkManager)__instance).maxConnections;
				((NetworkManager)__instance).maxConnections = ModConfig.CapValue;
				Plugin.Log.LogInfo((object)$"[LL] cap: maxConnections {maxConnections} -> {((NetworkManager)__instance).maxConnections}");
			}
			catch (Exception e)
			{
				Plugin.Fault("Cap.Awake", e);
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobby), "HostLobby")]
	internal static class P_Cap_HostLobby
	{
		private static void Prefix()
		{
			Apply.Cap("HostLobby");
		}
	}
	public static class Apply
	{
		public static void Cap(string where, bool quiet = false)
		{
			try
			{
				NetworkManager singleton = NetworkManager.singleton;
				if ((Object)(object)singleton == (Object)null)
				{
					return;
				}
				int capValue = ModConfig.CapValue;
				if (singleton.maxConnections != capValue)
				{
					if (quiet)
					{
						Plugin.Log.LogInfo((object)$"[LL] cap: maxConnections {singleton.maxConnections} -> {capValue} ({where})");
					}
					else
					{
						Plugin.Log.LogWarning((object)$"[LL] cap: maxConnections was {singleton.maxConnections} at {where}, forcing {capValue}");
					}
					singleton.maxConnections = capValue;
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Cap." + where, e);
			}
		}
	}
	[HarmonyPatch(typeof(NetworkManager), "StartHost")]
	[HarmonyPriority(600)]
	internal static class P_Cap_StartHost
	{
		private static void Postfix()
		{
			try
			{
				int capValue = ModConfig.CapValue;
				if (NetworkServer.maxConnections != capValue)
				{
					Plugin.Log.LogWarning((object)$"[LL] cap: NetworkServer.maxConnections was {NetworkServer.maxConnections}, forcing {capValue}");
					NetworkServer.maxConnections = capValue;
				}
				Transport active = Transport.active;
				if ((Object)(object)active == (Object)null)
				{
					return;
				}
				object value = Traverse.Create((object)active).Field("server").GetValue();
				if (value == null)
				{
					return;
				}
				Traverse val = Traverse.Create(value).Field("maxConnections");
				if (val.FieldExists())
				{
					int num = (int)val.GetValue();
					if (num != capValue)
					{
						Plugin.Log.LogWarning((object)$"[LL] cap: transport server maxConnections was {num}, forcing {capValue}");
						val.SetValue((object)capValue);
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Cap.StartHost", e);
			}
		}
	}
	[HarmonyPatch(typeof(GameManager), "GetAvailablePlayerIndex")]
	internal static class P_Cap_Index
	{
		private static readonly HashSet<int> Used = new HashSet<int>();

		private static bool Prefix(GameManager __instance, ref int __result)
		{
			try
			{
				Used.Clear();
				List<PlayerController> players = __instance.players;
				for (int i = 0; i < players.Count; i++)
				{
					if ((Object)(object)players[i] != (Object)null)
					{
						Used.Add(players[i].index);
					}
				}
				__result = RoomMath.LowestFreeIndex(Used, ModConfig.CapValue);
				return false;
			}
			catch (Exception e)
			{
				Plugin.Fault("Cap.Index", e);
				return true;
			}
		}
	}
	public static class HostPanelUi
	{
		public const string LabelName = "LL_MaxPlayersLabel";

		public const string SliderName = "LL_MaxPlayersSlider";

		public const int SliderMin = 4;

		private const float RowY = -427f;

		private const float OldTopY = -320.93f;

		private const float OldPitch = 83.07f;

		private const float NewTopY = -311f;

		private const float NewPitch = 58f;

		private static readonly FieldRef<HostPanelController, Toggle> ChillToggle = AccessTools.FieldRefAccess<HostPanelController, Toggle>("_chillModeToggle");

		private static readonly FieldRef<HostPanelController, GameObject> HolidayRow = AccessTools.FieldRefAccess<HostPanelController, GameObject>("_holidayThemeRow");

		private static bool _hierarchyLogged;

		public static string Label(int cap)
		{
			return $"MAX PLAYERS: {cap}";
		}

		public static GameObject Ensure(HostPanelController panel)
		{
			//IL_009b: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Expected O, but got Unknown
			//IL_01e7: 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_0210: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)panel == (Object)null)
			{
				return null;
			}
			Toggle val = ChillToggle.Invoke(panel);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[LL] hostpanel: no _chillModeToggle to clone");
				return null;
			}
			Transform val2 = FindRow(((Component)val).transform, HolidayRow.Invoke(panel));
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[LL] hostpanel: could not identify the chill-mode row");
				return null;
			}
			Transform parent = val2.parent;
			Transform val3 = parent.Find("LL_MaxPlayersLabel");
			if ((Object)(object)val3 != (Object)null)
			{
				if ((Object)(object)parent.Find("LL_MaxPlayersSlider") == (Object)null)
				{
					AddSlider(parent, ((Component)val3).gameObject, ((RectTransform)val3).anchoredPosition.x);
				}
				Refresh(parent);
				return ((Component)val3).gameObject;
			}
			if (!_hierarchyLogged)
			{
				_hierarchyLogged = true;
				Plugin.Log.LogInfo((object)("[LL] hostpanel template: " + UiKit.Describe(val2, 2)));
			}
			float num = float.MaxValue;
			foreach (RectTransform item in LabelRows(parent))
			{
				float x = item.anchoredPosition.x;
				if (x < num)
				{
					num = x;
				}
			}
			if (num == float.MaxValue)
			{
				num = -308f;
			}
			GameObject val4 = UiKit.CloneDetached(((Component)val2).gameObject, parent, "LL_MaxPlayersLabel");
			Toggle componentInChildren = val4.GetComponentInChildren<Toggle>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)((Component)componentInChildren).gameObject);
			}
			UiKit.Rect(val4).anchoredPosition = new Vector2(num, -427f);
			TMP_Text val5 = UiKit.FirstText(val4);
			if ((Object)(object)val5 != (Object)null)
			{
				((Graphic)val5).raycastTarget = false;
			}
			UiKit.SetText(val4, Label(ModConfig.CapValue));
			val4.SetActive(true);
			foreach (RectTransform item2 in LabelRows(parent))
			{
				RectTransform val6 = item2;
				float num2 = -311f + (val6.anchoredPosition.y - -320.93f) * 0.6982063f;
				val6.anchoredPosition = new Vector2(val6.anchoredPosition.x, num2);
			}
			bool flag = AddSlider(parent, val4, num);
			Plugin.Log.LogInfo((object)$"[LL] hostpanel: max-players row added (slider={flag}, container={((Object)parent).name})");
			return val4;
		}

		private static bool AddSlider(Transform container, GameObject label, float leftX)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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_00af: 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)
			Slider val = FindMenuSlider();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[LL] hostpanel: no Settings slider to clone yet; cap stays config-only until the panel is reopened");
				return false;
			}
			GameObject obj = UiKit.CloneDetached(((Component)val).gameObject, container, "LL_MaxPlayersSlider");
			RectTransform val2 = UiKit.Rect(obj);
			UiKit.Place(val2, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(leftX + 181f + 40f + 290f, -427f), new Vector2(580f, (val2.sizeDelta.y > 0f) ? val2.sizeDelta.y : 46f));
			UiKit.BindSlider(obj, 4f, 16f, whole: true, ModConfig.CapValue, "HostPanel.Slider", delegate(float v)
			{
				int num = Mathf.Clamp(Mathf.RoundToInt(v), 4, 16);
				if (ModConfig.Cap != null && ModConfig.Cap.Value != num)
				{
					ModConfig.Cap.Value = num;
				}
				UiKit.SetText(label, Label(ModConfig.CapValue));
				Apply.Cap("HostPanel", quiet: true);
			});
			obj.SetActive(true);
			return true;
		}

		public static void Refresh(Transform container)
		{
			Transform val = container.Find("LL_MaxPlayersLabel");
			if ((Object)(object)val != (Object)null)
			{
				UiKit.SetText(((Component)val).gameObject, Label(ModConfig.CapValue));
			}
			Transform val2 = container.Find("LL_MaxPlayersSlider");
			Slider val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponentInChildren<Slider>(true) : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.SetValueWithoutNotify((float)ModConfig.CapValue);
			}
		}

		public static Slider FindSlider(GameObject label)
		{
			Transform val = (((Object)(object)label != (Object)null && (Object)(object)label.transform.parent != (Object)null) ? label.transform.parent.Find("LL_MaxPlayersSlider") : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return ((Component)val).GetComponentInChildren<Slider>(true);
		}

		public static string CurrentLabel(GameObject label)
		{
			return UiKit.GetText(label);
		}

		private static IEnumerable<Transform> LabelRows(Transform container)
		{
			for (int i = 0; i < container.childCount; i++)
			{
				Transform child = container.GetChild(i);
				if (!(((Object)child).name == "LL_MaxPlayersLabel") && !(((Object)child).name == "LL_MaxPlayersSlider") && (Object)(object)((Component)child).GetComponent<TMP_Text>() != (Object)null && (Object)(object)((Component)child).GetComponentInChildren<Toggle>(true) != (Object)null)
				{
					yield return child;
				}
			}
		}

		private static Transform FindRow(Transform toggle, GameObject holidayRow)
		{
			if ((Object)(object)holidayRow != (Object)null && (Object)(object)holidayRow.transform.parent != (Object)null)
			{
				Transform parent = holidayRow.transform.parent;
				Transform val = toggle;
				while ((Object)(object)val != (Object)null && (Object)(object)val.parent != (Object)null)
				{
					if ((Object)(object)val.parent == (Object)(object)parent)
					{
						return val;
					}
					val = val.parent;
				}
			}
			Transform parent2 = toggle.parent;
			if ((Object)(object)parent2 != (Object)null && (Object)(object)parent2.parent != (Object)null && ((Component)parent2).GetComponentsInChildren<Toggle>(true).Length == 1)
			{
				return parent2;
			}
			return null;
		}

		private static Slider FindMenuSlider()
		{
			SettingsPanel val = Object.FindFirstObjectByType<SettingsPanel>((FindObjectsInactive)1);
			if ((Object)(object)val != (Object)null && SettingsUi.Locate(val, out var _, out var _, out var fov))
			{
				return fov;
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(HostPanelController), "OnEnable")]
	internal static class P_HostPanel_OnEnable
	{
		private static void Postfix(HostPanelController __instance)
		{
			try
			{
				HostPanelUi.Ensure(__instance);
			}
			catch (Exception e)
			{
				Plugin.Fault("HostPanel.OnEnable", e);
			}
		}
	}
	internal static class Owner
	{
		public static bool Shares(int playerIndex, int roomIndex)
		{
			if (roomIndex < 0 || playerIndex < 0)
			{
				return false;
			}
			if (Rooms.ShareAll)
			{
				return true;
			}
			int count = Rooms.Count;
			if (RoomMath.NeedsMapping(playerIndex, count))
			{
				return RoomMath.RoomIndex(playerIndex, count) == roomIndex;
			}
			return false;
		}

		public static int BedSlot(int playerIndex, int bedIndex)
		{
			if (Rooms.ShareAll)
			{
				return RoomMath.BedSlot(playerIndex, bedIndex);
			}
			int count = Rooms.Count;
			if (!RoomMath.NeedsMapping(playerIndex, count))
			{
				return 0;
			}
			return RoomMath.Occupant(playerIndex, count);
		}

		public static PlayerController ControllerOf(BadgeReader reader)
		{
			if ((Object)(object)reader == (Object)null || !reader.HasBadgeAuthoritative)
			{
				return null;
			}
			Player signedInPlayer = reader.SignedInPlayer;
			if (!((Object)(object)signedInPlayer != (Object)null))
			{
				return null;
			}
			return signedInPlayer.playerController;
		}
	}
	[HarmonyPatch(typeof(QuartersDoor), "ReaderHoldsAssignedPlayer")]
	internal static class P_Door_Holds
	{
		private static readonly FieldRef<QuartersDoor, int> Assigned = AccessTools.FieldRefAccess<QuartersDoor, int>("_assignedPlayerIndex");

		private static void Postfix(QuartersDoor __instance, BadgeReader reader, ref bool __result)
		{
			try
			{
				if (!__result)
				{
					PlayerController val = Owner.ControllerOf(reader);
					if ((Object)(object)val != (Object)null && Owner.Shares(val.index, Assigned.Invoke(__instance)))
					{
						__result = true;
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Door.Holds", e);
			}
		}
	}
	[HarmonyPatch(typeof(QuartersDoor), "HasUnauthorizedBadge")]
	internal static class P_Door_Unauthorized
	{
		private static readonly FieldRef<QuartersDoor, int> Assigned = AccessTools.FieldRefAccess<QuartersDoor, int>("_assignedPlayerIndex");

		private static void Postfix(QuartersDoor __instance, BadgeReader reader, ref bool __result)
		{
			try
			{
				if (__result)
				{
					PlayerController val = Owner.ControllerOf(reader);
					if ((Object)(object)val != (Object)null && Owner.Shares(val.index, Assigned.Invoke(__instance)))
					{
						__result = false;
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Door.Unauthorized", e);
			}
		}
	}
	internal static class BedFields
	{
		public static readonly FieldRef<Bed, int> PlayerIndex = AccessTools.FieldRefAccess<Bed, int>("_playerIndex");
	}
	[HarmonyPatch(typeof(Bed), "CanInteract")]
	internal static class P_Bed_CanInteract
	{
		private static void Postfix(Bed __instance, PlayerItemHolder holder, ref bool __result)
		{
			try
			{
				if (__result || (Object)(object)holder == (Object)null)
				{
					return;
				}
				int num = BedFields.PlayerIndex.Invoke(__instance);
				if (num >= 0 && !((Object)(object)BreakManager.instance == (Object)null) && BreakManager.instance.IsSleepPhase)
				{
					Player player = holder.Player;
					if (!((Object)(object)player == (Object)null) && !((Object)(object)player.playerController == (Object)null) && !player.IsSleepingInBed && Owner.Shares(player.playerController.index, num))
					{
						__result = true;
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Bed.CanInteract", e);
			}
		}
	}
	[HarmonyPatch(typeof(Bed), "Interact")]
	internal static class P_Bed_Interact
	{
		private static bool Prefix(Bed __instance, PlayerItemHolder holder)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)holder == (Object)null || (Object)(object)__instance.SleepPoint == (Object)null)
				{
					return true;
				}
				Player player = holder.Player;
				if ((Object)(object)player == (Object)null || (Object)(object)player.playerController == (Object)null)
				{
					return true;
				}
				int num = Owner.BedSlot(player.playerController.index, BedFields.PlayerIndex.Invoke(__instance));
				if (num <= 0)
				{
					return true;
				}
				Vector3 val = Rooms.OffsetPosition(__instance.SleepPoint, num);
				player.RequestSleepInBed(val);
				return false;
			}
			catch (Exception e)
			{
				Plugin.Fault("Bed.Interact", e);
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(Bed), "GetForPlayer")]
	internal static class P_Bed_GetForPlayer
	{
		private static void Postfix(int playerIndex, ref Bed __result)
		{
			try
			{
				if (!((Object)(object)__result != (Object)null))
				{
					int count = Rooms.Count;
					if (RoomMath.NeedsMapping(playerIndex, count))
					{
						__result = Bed.GetForPlayer(RoomMath.RoomIndex(playerIndex, count));
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Bed.GetForPlayer", e);
			}
		}
	}
	internal static class WardrobeFields
	{
		public static readonly FieldRef<Wardrobe, int> PlayerIndex = AccessTools.FieldRefAccess<Wardrobe, int>("_playerIndex");

		public const int NoSwap = int.MinValue;

		public static int SwapFor(Wardrobe w, PlayerController pc)
		{
			if ((Object)(object)pc == (Object)null)
			{
				return int.MinValue;
			}
			int num = PlayerIndex.Invoke(w);
			if (!Owner.Shares(pc.index, num))
			{
				return int.MinValue;
			}
			PlayerIndex.Invoke(w) = pc.index;
			return num;
		}

		public static void Restore(Wardrobe w, int state)
		{
			try
			{
				if (state != int.MinValue)
				{
					PlayerIndex.Invoke(w) = state;
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Wardrobe.Restore", e);
			}
		}
	}
	[HarmonyPatch(typeof(Wardrobe), "IsAssignedPlayer")]
	internal static class P_Wardrobe_IsAssigned
	{
		private static void Postfix(Wardrobe __instance, PlayerItemHolder holder, ref bool __result)
		{
			try
			{
				if (!__result && !((Object)(object)holder == (Object)null))
				{
					Player player = holder.Player;
					if (!((Object)(object)player == (Object)null) && !((Object)(object)player.playerController == (Object)null) && Owner.Shares(player.playerController.index, WardrobeFields.PlayerIndex.Invoke(__instance)))
					{
						__result = true;
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Wardrobe.IsAssigned", e);
			}
		}
	}
	[HarmonyPatch(typeof(Wardrobe), "ServerCycle")]
	internal static class P_Wardrobe_ServerCycle
	{
		private static void Prefix(Wardrobe __instance, Player presser, ref int __state)
		{
			__state = int.MinValue;
			try
			{
				__state = WardrobeFields.SwapFor(__instance, ((Object)(object)presser != (Object)null) ? presser.playerController : null);
			}
			catch (Exception e)
			{
				Plugin.Fault("Wardrobe.ServerCycle", e);
			}
		}

		private static void Finalizer(Wardrobe __instance, int __state)
		{
			WardrobeFields.Restore(__instance, __state);
		}
	}
	[HarmonyPatch(typeof(Wardrobe), "UserCode_CmdEquip__NetworkConnectionToClient")]
	internal static class P_Wardrobe_CmdEquip
	{
		private static void Prefix(Wardrobe __instance, NetworkConnectionToClient sender, ref int __state)
		{
			__state = int.MinValue;
			try
			{
				PlayerController pc = ((sender != null && (Object)(object)((NetworkConnection)sender).identity != (Object)null) ? ((Component)((NetworkConnection)sender).identity).GetComponent<PlayerController>() : null);
				__state = WardrobeFields.SwapFor(__instance, pc);
			}
			catch (Exception e)
			{
				Plugin.Fault("Wardrobe.CmdEquip", e);
			}
		}

		private static void Finalizer(Wardrobe __instance, int __state)
		{
			WardrobeFields.Restore(__instance, __state);
		}
	}
	public static class Rooms
	{
		private static readonly FieldRef<List<QuartersRoom>> AllRef = AccessTools.StaticFieldRefAccess<List<QuartersRoom>>(AccessTools.Field(typeof(QuartersRoom), "_all"));

		private static int _cachedFrame = -1;

		private static int _cachedCount;

		public static int Count
		{
			get
			{
				if (_cachedFrame == Time.frameCount)
				{
					return _cachedCount;
				}
				_cachedFrame = Time.frameCount;
				_cachedCount = Compute();
				return _cachedCount;
			}
		}

		public static bool ShareAll
		{
			get
			{
				if (ModConfig.ShareAllRooms != null)
				{
					return ModConfig.ShareAllRooms.Value;
				}
				return false;
			}
		}

		public static void Invalidate()
		{
			_cachedFrame = -1;
		}

		private static int Compute()
		{
			List<QuartersRoom> list = AllRef.Invoke();
			if (list == null || list.Count == 0)
			{
				return 0;
			}
			int num = -1;
			for (int i = 0; i < list.Count; i++)
			{
				QuartersRoom val = list[i];
				if ((Object)(object)val != (Object)null && val.PlayerIndex > num)
				{
					num = val.PlayerIndex;
				}
			}
			return num + 1;
		}

		public static Vector3 OffsetPosition(Transform anchor, int occupant)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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)
			float step = ((ModConfig.SpawnOffsetMeters != null) ? ModConfig.SpawnOffsetMeters.Value : 0.7f);
			RoomMath.Offset(occupant, step, out var right, out var forward);
			return anchor.position + anchor.right * right + anchor.forward * forward;
		}
	}
	internal static class Scaling
	{
		public static bool On
		{
			get
			{
				if (ModConfig.ScaleEvents != null)
				{
					return ModConfig.ScaleEvents.Value;
				}
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(DailyTaskManager), "TargetFor")]
	internal static class P_Scale_WorkOrder
	{
		private static readonly FieldRef<WorkOrderStep, int[]> Table = AccessTools.FieldRefAccess<WorkOrderStep, int[]>("amountByCrew");

		private static void Postfix(WorkOrderStep step, ref int __result)
		{
			try
			{
				if (Scaling.On && step != null && step.HasCrewAmounts)
				{
					int[] array = Table.Invoke(step);
					int playerCount = GameManager.PlayerCount;
					if (array != null && playerCount > array.Length)
					{
						__result = Math.Max(1, RoomMath.Extrapolate(array, playerCount));
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Scale.WorkOrder", e);
			}
		}
	}
	[HarmonyPatch(typeof(CandyDropEvent), "CountForCrew")]
	internal static class P_Scale_Candy
	{
		private static readonly FieldRef<CandyDropEvent, int[]> Table = AccessTools.FieldRefAccess<CandyDropEvent, int[]>("countByCrew");

		private static void Postfix(CandyDropEvent __instance, int crew, ref int __result)
		{
			try
			{
				if (Scaling.On)
				{
					int[] array = Table.Invoke(__instance);
					if (array != null && crew > array.Length)
					{
						__result = Math.Max(0, RoomMath.Extrapolate(array, crew));
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Scale.Candy", e);
			}
		}
	}
	[HarmonyPatch(typeof(PowerCutEvent), "ServerDispenseLanterns")]
	internal static class P_Scale_Lanterns
	{
		private static readonly FieldRef<PowerCutEvent, int> Max = AccessTools.FieldRefAccess<PowerCutEvent, int>("maxLanterns");

		private static void Prefix(PowerCutEvent __instance)
		{
			try
			{
				if (Scaling.On && Max.Invoke(__instance) < ModConfig.CapValue)
				{
					Max.Invoke(__instance) = ModConfig.CapValue;
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Scale.Lanterns", e);
			}
		}
	}
	[HarmonyPatch(typeof(HappyHourEvent), "ServerPillCount")]
	internal static class P_Scale_Pills
	{
		private static readonly FieldRef<HappyHourEvent, int> Max = AccessTools.FieldRefAccess<HappyHourEvent, int>("maxPills");

		private static readonly FieldRef<HappyHourEvent, int> PerPlayer = AccessTools.FieldRefAccess<HappyHourEvent, int>("pillsPerPlayer");

		private static void Prefix(HappyHourEvent __instance)
		{
			try
			{
				if (Scaling.On)
				{
					int num = ModConfig.CapValue * Math.Max(1, PerPlayer.Invoke(__instance));
					if (Max.Invoke(__instance) < num)
					{
						Max.Invoke(__instance) = num;
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Scale.Pills", e);
			}
		}
	}
	[HarmonyPatch(typeof(BalanceDisplayApp), "ServerRebuild")]
	internal static class P_Scale_BalanceRows
	{
		private static readonly FieldRef<BalanceDisplayApp, int> Rows = AccessTools.FieldRefAccess<BalanceDisplayApp, int>("maxRows");

		private static void Prefix(BalanceDisplayApp __instance)
		{
			try
			{
				if (Scaling.On && Rows.Invoke(__instance) > 0 && Rows.Invoke(__instance) < ModConfig.CapValue)
				{
					Rows.Invoke(__instance) = ModConfig.CapValue;
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Scale.BalanceRows", e);
			}
		}
	}
	[HarmonyPatch(typeof(EfficiencyDisplayApp), "ServerRebuild")]
	internal static class P_Scale_EfficiencyRows
	{
		private static readonly FieldRef<EfficiencyDisplayApp, int> Rows = AccessTools.FieldRefAccess<EfficiencyDisplayApp, int>("maxRows");

		private static void Prefix(EfficiencyDisplayApp __instance)
		{
			try
			{
				if (Scaling.On && Rows.Invoke(__instance) > 0 && Rows.Invoke(__instance) < ModConfig.CapValue)
				{
					Rows.Invoke(__instance) = ModConfig.CapValue;
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Scale.EfficiencyRows", e);
			}
		}
	}
	public static class SettingsUi
	{
		public struct Tweak
		{
			public string Key;

			public string Label;

			public ConfigEntry<bool> Entry;
		}

		public const string CardName = "LL_LobbiesCard";

		private static readonly FieldRef<SettingsPanel, Slider> FovSlider = AccessTools.FieldRefAccess<SettingsPanel, Slider>("fieldOfViewSlider");

		public static Tweak[] Tweaks()
		{
			return new Tweak[3]
			{
				new Tweak
				{
					Key = "ShareAllRooms",
					Label = "SHARE ALL ROOMS",
					Entry = ModConfig.ShareAllRooms
				},
				new Tweak
				{
					Key = "ScaleEvents",
					Label = "SCALE EVENTS TO CREW",
					Entry = ModConfig.ScaleEvents
				},
				new Tweak
				{
					Key = "ExtendColors",
					Label = "EXTRA PLAYER COLOURS",
					Entry = ModConfig.ExtendColors
				}
			};
		}

		public static bool Locate(SettingsPanel panel, out Transform generalCard, out Transform generalContent, out Slider fov)
		{
			generalCard = null;
			generalContent = null;
			fov = null;
			if ((Object)(object)panel == (Object)null)
			{
				return false;
			}
			fov = FovSlider.Invoke(panel);
			if ((Object)(object)fov == (Object)null)
			{
				return false;
			}
			Transform parent = ((Component)fov).transform.parent;
			generalContent = (((Object)(object)parent != (Object)null) ? parent.parent : null);
			generalCard = (((Object)(object)generalContent != (Object)null) ? generalContent.parent : null);
			if ((Object)(object)generalCard != (Object)null)
			{
				return (Object)(object)generalCard.parent != (Object)null;
			}
			return false;
		}

		public static GameObject Ensure(SettingsPanel panel)
		{
			if (!Locate(panel, out var generalCard, out var generalContent, out var _))
			{
				Plugin.Log.LogWarning((object)"[LL] settings: could not locate the General card");
				return null;
			}
			Transform parent = generalCard.parent;
			Transform val = parent.Find("LL_LobbiesCard");
			if ((Object)(object)val != (Object)null)
			{
				Refresh(((Component)val).gameObject);
				return ((Component)val).gameObject;
			}
			Transform val2 = null;
			for (int i = 0; i < generalContent.childCount; i++)
			{
				Transform child = generalContent.GetChild(i);
				if ((Object)(object)((Component)child).GetComponentInChildren<Toggle>(true) != (Object)null && (Object)(object)((Component)child).GetComponentInChildren<TMP_Dropdown>(true) == (Object)null && (Object)(object)((Component)child).GetComponentInChildren<Slider>(true) == (Object)null)
				{
					val2 = child;
					break;
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[LL] settings: no toggle row to clone");
				return null;
			}
			GameObject val3 = UiKit.CloneDetached(((Component)generalCard).gameObject, parent, "LL_LobbiesCard");
			try
			{
				Build(val3, generalCard, val2);
			}
			catch (Exception)
			{
				Object.DestroyImmediate((Object)(object)val3);
				throw;
			}
			val3.SetActive(true);
			Plugin.Log.LogInfo((object)string.Format("[LL] settings: LARGER LOBBIES card added with {0} rows", val3.transform.Find("Content").childCount));
			return val3;
		}

		private static void Build(GameObject card, Transform generalCard, Transform toggleTemplate)
		{
			//IL_002b: 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_0042: 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)
			//IL_0058: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: 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_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			card.transform.SetSiblingIndex(generalCard.GetSiblingIndex() + 1);
			RectTransform obj = UiKit.Rect(card);
			RectTransform val = (RectTransform)(object)((generalCard is RectTransform) ? generalCard : null);
			obj.anchorMin = new Vector2(0f, 0f);
			obj.anchorMax = new Vector2(val.anchorMax.x, val.anchorMin.y);
			obj.offsetMin = new Vector2(val.offsetMin.x, 155f);
			obj.offsetMax = new Vector2(val.offsetMax.x, val.offsetMin.y - 12f);
			Transform val2 = card.transform.Find("Content");
			if ((Object)(object)val2 == (Object)null)
			{
				throw new InvalidOperationException("cloned card has no Content");
			}
			for (int num = val2.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)val2.GetChild(num)).gameObject);
			}
			Transform obj2 = ((val2 is RectTransform) ? val2 : null);
			((RectTransform)obj2).anchoredPosition = new Vector2(0f, -14f);
			((RectTransform)obj2).sizeDelta = new Vector2(((RectTransform)obj2).sizeDelta.x, -60f);
			VerticalLayoutGroup component = ((Component)val2).GetComponent<VerticalLayoutGroup>();
			if ((Object)(object)component != (Object)null)
			{
				((HorizontalOrVerticalLayoutGroup)component).spacing = 2f;
				((LayoutGroup)component).padding = new RectOffset(((LayoutGroup)component).padding.left, ((LayoutGroup)component).padding.right, 0, 0);
				((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false;
				((LayoutGroup)component).childAlignment = (TextAnchor)1;
			}
			for (int i = 0; i < card.transform.childCount; i++)
			{
				TMP_Text component2 = ((Component)card.transform.GetChild(i)).GetComponent<TMP_Text>();
				if (!((Object)(object)component2 == (Object)null))
				{
					component2.text = "LARGER LOBBIES";
					component2.fontSize *= 0.8f;
					RectTransform rectTransform = component2.rectTransform;
					rectTransform.anchoredPosition = new Vector2(rectTransform.anchoredPosition.x, -26f);
					break;
				}
			}
			Tweak[] array = Tweaks();
			for (int j = 0; j < array.Length; j++)
			{
				Tweak tw = array[j];
				ConfigEntry<bool> entry = tw.Entry;
				GameObject val3 = UiKit.CloneDetached(((Component)toggleTemplate).gameObject, val2, "LL_Row_" + tw.Key);
				UiKit.SetText(val3, tw.Label);
				TMP_Text val4 = UiKit.FirstText(val3);
				if ((Object)(object)val4 != (Object)null)
				{
					val4.fontSize *= 0.8f;
				}
				RectTransform obj3 = UiKit.Rect(val3);
				obj3.sizeDelta = new Vector2(obj3.sizeDelta.x, 42f);
				LayoutElement val5 = val3.GetComponent<LayoutElement>();
				if ((Object)(object)val5 == (Object)null)
				{
					val5 = val3.AddComponent<LayoutElement>();
				}
				val5.preferredHeight = 42f;
				val5.minHeight = 42f;
				Toggle componentInChildren = val3.GetComponentInChildren<Toggle>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					((Component)componentInChildren).transform.localScale = Vector3.one * 0.8f;
				}
				UiKit.BindToggle(val3, entry != null && entry.Value, "Settings." + tw.Key, delegate(bool v)
				{
					if (entry != null)
					{
						entry.Value = v;
					}
					Plugin.Log.LogInfo((object)$"[LL] settings: {tw.Key}={v}");
				});
				val3.SetActive(true);
			}
		}

		public static void Refresh(GameObject card)
		{
			Tweak[] array = Tweaks();
			for (int i = 0; i < array.Length; i++)
			{
				Tweak tweak = array[i];
				Transform val = card.transform.Find("Content/LL_Row_" + tweak.Key);
				Toggle val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<Toggle>(true) : null);
				if ((Object)(object)val2 != (Object)null && tweak.Entry != null)
				{
					val2.SetIsOnWithoutNotify(tweak.Entry.Value);
				}
			}
		}

		public static List<string> Verify(GameObject card)
		{
			List<string> list = new List<string>();
			if ((Object)(object)card == (Object)null)
			{
				list.Add("no card");
				return list;
			}
			Tweak[] array = Tweaks();
			for (int i = 0; i < array.Length; i++)
			{
				Tweak tweak = array[i];
				Transform val = card.transform.Find("Content/LL_Row_" + tweak.Key);
				Toggle val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<Toggle>(true) : null);
				if ((Object)(object)val == (Object)null)
				{
					list.Add(tweak.Key + ": no row");
				}
				else if ((Object)(object)val2 == (Object)null)
				{
					list.Add(tweak.Key + ": no toggle");
				}
				else if ((Object)(object)((Component)val).GetComponentInChildren<TMP_Dropdown>(true) != (Object)null)
				{
					list.Add(tweak.Key + ": cloned a dropdown row");
				}
				else if (tweak.Entry != null && val2.isOn != tweak.Entry.Value)
				{
					list.Add(tweak.Key + ": toggle != config");
				}
				else if (UiKit.GetText(((Component)val).gameObject) != tweak.Label)
				{
					list.Add(tweak.Key + ": label");
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(SettingsPanel), "OnEnable")]
	internal static class P_Settings_OnEnable
	{
		private static void Postfix(SettingsPanel __instance)
		{
			try
			{
				SettingsUi.Ensure(__instance);
			}
			catch (Exception e)
			{
				Plugin.Fault("Settings.OnEnable", e);
			}
		}
	}
	[HarmonyPatch(typeof(GameManager), "GetSpawnPoint")]
	internal static class P_Spawn_Point
	{
		private static bool Prefix(int playerIndex, ref (Vector3, Quaternion) __result)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int count = Rooms.Count;
				if (!RoomMath.NeedsMapping(playerIndex, count))
				{
					return true;
				}
				if ((Object)(object)QuartersRoom.Get(playerIndex) != (Object)null)
				{
					return true;
				}
				QuartersRoom val = QuartersRoom.Get(RoomMath.RoomIndex(playerIndex, count));
				if ((Object)(object)val == (Object)null || (Object)(object)val.SpawnPoint == (Object)null)
				{
					return true;
				}
				Transform spawnPoint = val.SpawnPoint;
				Vector3 val2 = Rooms.OffsetPosition(spawnPoint, RoomMath.Occupant(playerIndex, count));
				__result = (val2, spawnPoint.rotation);
				Plugin.Log.LogInfo((object)$"[LL] spawn: idx={playerIndex} shares room {val.PlayerIndex} at {val2}");
				return false;
			}
			catch (Exception e)
			{
				Plugin.Fault("Spawn.Point", e);
				return true;
			}
		}
	}
	public static class SummaryScroll
	{
		public const string ViewportName = "LL_RowsViewport";

		public const float HeaderInset = 44f;

		private static readonly FieldRef<ShiftCompleteUI, RectTransform> RowContainer = AccessTools.FieldRefAccess<ShiftCompleteUI, RectTransform>("_rowContainer");

		private static readonly FieldRef<ShiftCompleteUI, List<ShiftPlayerRow>> Rows = AccessTools.FieldRefAccess<ShiftCompleteUI, List<ShiftPlayerRow>>("_rows");

		private static float MeasureRows(ShiftCompleteUI ui, RectTransform container)
		{
			//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)
			List<ShiftPlayerRow> list = Rows.Invoke(ui);
			float num = 0f;
			int num2 = 0;
			if (list != null)
			{
				foreach (ShiftPlayerRow item in list)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					Transform transform = ((Component)item).transform;
					RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					Rect rect = val.rect;
					float num3 = ((Rect)(ref rect)).height;
					if (num3 <= 0f)
					{
						num3 = LayoutUtility.GetPreferredHeight(val);
					}
					if (num3 <= 0f)
					{
						continue;
					}
					if (LayoutUtility.GetPreferredHeight(val) < num3 - 0.5f)
					{
						LayoutElement val2 = ((Component)val).GetComponent<LayoutElement>();
						if ((Object)(object)val2 == (Object)null)
						{
							val2 = ((Component)val).gameObject.AddComponent<LayoutElement>();
						}
						val2.minHeight = num3;
						val2.preferredHeight = num3;
					}
					num += num3;
					num2++;
				}
			}
			HorizontalOrVerticalLayoutGroup component = ((Component)container).GetComponent<HorizontalOrVerticalLayoutGroup>();
			if ((Object)(object)component != (Object)null && num2 > 0)
			{
				num += component.spacing * (float)(num2 - 1) + (float)((LayoutGroup)component).padding.top + (float)((LayoutGroup)component).padding.bottom;
			}
			return num;
		}

		public static void OnShow(ShiftCompleteUI ui)
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = RowContainer.Invoke(ui);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			ScrollRect val2 = (((Object)(object)((Transform)val).parent != (Object)null && ((Object)((Transform)val).parent).name == "LL_RowsViewport") ? ((Component)((Transform)val).parent).GetComponent<ScrollRect>() : null);
			Rect rect;
			if ((Object)(object)val2 == (Object)null)
			{
				LayoutGroup component = ((Component)val).GetComponent<LayoutGroup>();
				if (!(component is VerticalLayoutGroup) && !(component is GridLayoutGroup))
				{
					Plugin.Log.LogWarning((object)("[LL] summary: row container layout is " + (((Object)(object)component != (Object)null) ? ((object)component).GetType().Name : "none") + "; not wrapping"));
					return;
				}
				float num = MeasureRows(ui, val);
				rect = val.rect;
				float height = ((Rect)(ref rect)).height;
				if (num <= height + 1f)
				{
					Plugin.Log.LogInfo((object)$"[LL] summary: rows fit ({num:F0} of {height:F0} px); no scroll view");
					return;
				}
				val2 = Wrap(val, height);
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				Plugin.Log.LogInfo((object)$"[LL] summary: rows overflow ({num:F0} of {height:F0} px); scroll view added");
			}
			else
			{
				float num2 = MeasureRows(ui, val);
				rect = val2.viewport.rect;
				bool enabled = (((Behaviour)val2).enabled = num2 > ((Rect)(ref rect)).height + 1f);
				RectMask2D component2 = ((Component)val2).GetComponent<RectMask2D>();
				if ((Object)(object)component2 != (Object)null)
				{
					((Behaviour)component2).enabled = enabled;
				}
			}
			Reset(val2);
		}

		private static ScrollRect Wrap(RectTransform container, float availableHeight)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = ((Transform)container).parent;
			if ((Object)(object)parent == (Object)null)
			{
				return null;
			}
			int siblingIndex = ((Transform)container).GetSiblingIndex();
			float minWidth = LayoutUtility.GetMinWidth(container);
			float preferredWidth = LayoutUtility.GetPreferredWidth(container);
			float flexibleWidth = LayoutUtility.GetFlexibleWidth(container);
			float minHeight = LayoutUtility.GetMinHeight(container);
			float flexibleHeight = LayoutUtility.GetFlexibleHeight(container);
			GameObject val = new GameObject("LL_RowsViewport", new Type[4]
			{
				typeof(RectTransform),
				typeof(RectMask2D),
				typeof(ScrollRect),
				typeof(SummaryScrollInput)
			});
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			((Transform)val2).SetSiblingIndex(siblingIndex);
			val2.anchorMin = container.anchorMin;
			val2.anchorMax = container.anchorMax;
			val2.pivot = container.pivot;
			val2.anchoredPosition = container.anchoredPosition;
			val2.sizeDelta = container.sizeDelta;
			((Transform)val2).localScale = ((Transform)container).localScale;
			((Transform)val2).localRotation = ((Transform)container).localRotation;
			val2.offsetMax = new Vector2(val2.offsetMax.x, val2.offsetMax.y - 44f);
			if ((Object)(object)((Component)parent).GetComponent<LayoutGroup>() != (Object)null)
			{
				LayoutElement obj = val.AddComponent<LayoutElement>();
				obj.minWidth = minWidth;
				obj.preferredWidth = preferredWidth;
				obj.flexibleWidth = flexibleWidth;
				obj.minHeight = minHeight;
				obj.preferredHeight = availableHeight;
				obj.flexibleHeight = flexibleHeight;
			}
			((Transform)container).SetParent((Transform)(object)val2, false);
			container.anchorMin = new Vector2(0f, 1f);
			container.anchorMax = new Vector2(1f, 1f);
			container.pivot = new Vector2(0.5f, 1f);
			container.anchoredPosition = Vector2.zero;
			container.sizeDelta = new Vector2(0f, availableHeight);
			LayoutElement component = ((Component)container).GetComponent<LayoutElement>();
			if ((Object)(object)component != (Object)null)
			{
				component.ignoreLayout = false;
			}
			ContentSizeFitter val3 = ((Component)container).GetComponent<ContentSizeFitter>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = ((Component)container).gameObject.AddComponent<ContentSizeFitter>();
			}
			val3.verticalFit = (FitMode)2;
			val3.horizontalFit = (FitMode)0;
			ScrollRect component2 = val.GetComponent<ScrollRect>();
			component2.content = container;
			component2.viewport = val2;
			component2.horizontal = false;
			component2.vertical = true;
			component2.movementType = (MovementType)2;
			component2.inertia = false;
			component2.scrollSensitivity = 40f;
			return component2;
		}

		private static void Reset(ScrollRect scroll)
		{
			if (!((Object)(object)scroll == (Object)null) && !((Object)(object)scroll.content == (Object)null))
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(scroll.content);
				scroll.StopMovement();
				scroll.verticalNormalizedPosition = 1f;
			}
		}

		public static ScrollRect Find(ShiftCompleteUI ui)
		{
			RectTransform val = RowContainer.Invoke(ui);
			if (!((Object)(object)val != (Object)null) || !((Object)(object)((Transform)val).parent != (Object)null))
			{
				return null;
			}
			return ((Component)((Transform)val).parent).GetComponent<ScrollRect>();
		}

		public static void Follow(ShiftPlayerRow row)
		{
			if ((Object)(object)row == (Object)null)
			{
				return;
			}
			Transform transform = ((Component)row).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			RectTransform val2 = (RectTransform)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null);
			ScrollRect val3 = (((Object)(object)val2 != (Object)null && (Object)(object)((Transform)val2).parent != (Object)null) ? ((Component)((Transform)val2).parent).GetComponent<ScrollRect>() : null);
			if (!((Object)(object)val3 == (Object)null) && ((Behaviour)val3).enabled && !((Object)(object)val3.viewport == (Object)null))
			{
				SummaryScrollInput component = ((Component)val3).GetComponent<SummaryScrollInput>();
				if ((Object)(object)component != (Object)null)
				{
					component.RevealRow(val);
				}
			}
		}

		public static float ScrollTo(ShiftCompleteUI ui, float normalized)
		{
			ScrollRect val = Find(ui);
			if ((Object)(object)val == (Object)null)
			{
				return -1f;
			}
			SummaryScrollInput component = ((Component)val).GetComponent<SummaryScrollInput>();
			if ((Object)(object)component != (Object)null)
			{
				component.CancelFollow(10f);
			}
			val.verticalNormalizedPosition = normalized;
			return val.verticalNormalizedPosition;
		}

		public static string Describe(ShiftCompleteUI ui)
		{
			//IL_0048: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = RowContainer.Invoke(ui);
			if ((Object)(object)val == (Object)null)
			{
				return "no container";
			}
			ScrollRect val2 = Find(ui);
			LayoutRebuilder.ForceRebuildLayoutImmediate(val);
			float preferredHeight = LayoutUtility.GetPreferredHeight(val);
			Rect rect;
			float height;
			if (!((Object)(object)val2 != (Object)null) || !((Object)(object)val2.viewport != (Object)null))
			{
				rect = val.rect;
				height = ((Rect)(ref rect)).height;
			}
			else
			{
				rect = val2.viewport.rect;
				height = ((Rect)(ref rect)).height;
			}
			float num = height;
			int num2 = 0;
			for (int i = 0; i < ((Transform)val).childCount; i++)
			{
				if (((Component)((Transform)val).GetChild(i)).gameObject.activeSelf && (Object)(object)((Component)((Transform)val).GetChild(i)).GetComponent<ShiftPlayerRow>() != (Object)null)
				{
					num2++;
				}
			}
			return $"rows={num2} contentH={preferredHeight:F0} viewportH={num:F0} scroll={(Object)(object)val2 != (Object)null && ((Behaviour)val2).enabled} scrollable={(Object)(object)val2 != (Object)null && ((Behaviour)val2).enabled && preferredHeight > num + 1f}";
		}
	}
	public class SummaryScrollInput : MonoBehaviour
	{
		private ScrollRect _scroll;

		private float _target = -1f;

		private float _idleUntil;

		private void Awake()
		{
			_scroll = ((Component)this).GetComponent<ScrollRect>();
		}

		public void RevealRow(RectTransform row)
		{
			//IL_005e: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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)
			if (!((Object)(object)_scroll == (Object)null) && !((Object)(object)_scroll.content == (Object)null) && !((Object)(object)_scroll.viewport == (Object)null) && !(Time.unscaledTime < _idleUntil))
			{
				LayoutRebuilder.ForceRebuildLayoutImmediate(_scroll.content);
				Rect rect = _scroll.content.rect;
				float height = ((Rect)(ref rect)).height;
				rect = _scroll.viewport.rect;
				float height2 = ((Rect)(ref rect)).height;
				float num = height - height2;
				if (!(num <= 1f))
				{
					float num2 = 0f - row.anchoredPosition.y;
					rect = row.rect;
					float num3 = num2 - ((Rect)(ref rect)).height * (1f - row.pivot.y);
					rect = row.rect;
					float num4 = Mathf.Clamp(num3 + ((Rect)(ref rect)).height - height2 + 8f, 0f, num);
					_target = 1f - num4 / num;
				}
			}
		}

		public void CancelFollow(float holdSeconds = 0f)
		{
			_target = -1f;
			if (holdSeconds > 0f)
			{
				_idleUntil = Time.unscaledTime + holdSeconds;
			}
		}

		private void Update()
		{
			//IL_004d: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_scroll == (Object)null || !((Behaviour)_scroll).enabled || (Object)(object)_scroll.content == (Object)null || (Object)(object)_scroll.viewport == (Object)null)
			{
				return;
			}
			Rect rect = _scroll.content.rect;
			float height = ((Rect)(ref rect)).height;
			rect = _scroll.viewport.rect;
			float height2 = ((Rect)(ref rect)).height;
			float num = height - height2;
			if (num <= 1f)
			{
				return;
			}
			float num2 = 0f;
			try
			{
				Mouse current = Mouse.current;
				if (current != null)
				{
					num2 -= ((InputControl<Vector2>)(object)current.scroll).ReadValue().y * 0.6f;
				}
				Keyboard current2 = Keyboard.current;
				if (current2 != null)
				{
					float num3 = 420f * Time.unscaledDeltaTime;
					if (((ButtonControl)current2.downArrowKey).isPressed)
					{
						num2 += num3;
					}
					if (((ButtonControl)current2.upArrowKey).isPressed)
					{
						num2 -= num3;
					}
					if (((ButtonControl)current2.pageDownKey).wasPressedThisFrame)
					{
						num2 += height2 * 0.8f;
					}
					if (((ButtonControl)current2.pageUpKey).wasPressedThisFrame)
					{
						num2 -= height2 * 0.8f;
					}
				}
				Gamepad current3 = Gamepad.current;
				if (current3 != null)
				{
					float y = ((InputControl<Vector2>)(object)current3.rightStick).ReadValue().y;
					if (Mathf.Abs(y) > 0.25f)
					{
						num2 -= y * 600f * Time.unscaledDeltaTime;
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Summary.Input", e);
				((Behaviour)this).enabled = false;
				return;
			}
			if (Mathf.Abs(num2) > 0.01f)
			{
				_target = -1f;
				_idleUntil = Time.unscaledTime + 2f;
				_scroll.verticalNormalizedPosition = Mathf.Clamp01(_scroll.verticalNormalizedPosition - num2 / num);
			}
			else if (_target >= 0f)
			{
				float num4 = Mathf.MoveTowards(_scroll.verticalNormalizedPosition, _target, Time.unscaledDeltaTime * 2.5f);
				_scroll.verticalNormalizedPosition = num4;
				if (Mathf.Abs(num4 - _target) < 0.001f)
				{
					_target = -1f;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShiftCompleteUI), "Show")]
	internal static class P_Summary_Show
	{
		private static void Postfix(ShiftCompleteUI __instance)
		{
			try
			{
				SummaryScroll.OnShow(__instance);
			}
			catch (Exception e)
			{
				Plugin.Fault("Summary.Scroll", e);
			}
		}
	}
	[HarmonyPatch(typeof(ShiftPlayerRow), "PlayIn")]
	internal static class P_Summary_RowPlayIn
	{
		private static void Postfix(ShiftPlayerRow __instance)
		{
			try
			{
				SummaryScroll.Follow(__instance);
			}
			catch (Exception e)
			{
				Plugin.Fault("Summary.Follow", e);
			}
		}
	}
	public static class UiKit
	{
		public static GameObject CloneDetached(GameObject template, Transform parent, string name)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			GameObject val = new GameObject("LL_holder");
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			GameObject obj = Object.Instantiate<GameObject>(template, val.transform);
			obj.SetActive(false);
			((Object)obj).name = name;
			Strip(obj);
			obj.transform.SetParent(parent, false);
			Object.DestroyImmediate((Object)(object)val);
			return obj;
		}

		public static void Strip(GameObject go)
		{
			LocalizedText[] componentsInChildren = go.GetComponentsInChildren<LocalizedText>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			HoverHint[] componentsInChildren2 = go.GetComponentsInChildren<HoverHint>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
		}

		public static TMP_Text FirstText(GameObject go)
		{
			if (!((Object)(object)go != (Object)null))
			{
				return null;
			}
			return go.GetComponentInChildren<TMP_Text>(true);
		}

		public static void SetText(GameObject go, string text)
		{
			TMP_Text val = FirstText(go);
			if ((Object)(object)val != (Object)null)
			{
				val.text = text;
			}
		}

		public static string GetText(GameObject go)
		{
			TMP_Text val = FirstText(go);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.text;
		}

		public static Toggle BindToggle(GameObject row, bool initial, string site, Action<bool> onChanged)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			Toggle componentInChildren = row.GetComponentInChildren<Toggle>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return null;
			}
			componentInChildren.group = null;
			componentInChildren.onValueChanged = new ToggleEvent();
			componentInChildren.SetIsOnWithoutNotify(initial);
			((UnityEvent<bool>)(object)componentInChildren.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
			{
				try
				{
					onChanged(v);
				}
				catch (Exception e)
				{
					Plugin.Fault(site, e);
				}
			});
			return componentInChildren;
		}

		public static Slider BindSlider(GameObject sliderObject, float min, float max, bool whole, float initial, string site, Action<float> onChanged)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			Slider componentInChildren = sliderObject.GetComponentInChildren<Slider>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return null;
			}
			componentInChildren.onValueChanged = new SliderEvent();
			componentInChildren.minValue = min;
			componentInChildren.maxValue = max;
			componentInChildren.wholeNumbers = whole;
			componentInChildren.SetValueWithoutNotify(initial);
			((UnityEvent<float>)(object)componentInChildren.onValueChanged).AddListener((UnityAction<float>)delegate(float v)
			{
				try
				{
					onChanged(v);
				}
				catch (Exception e)
				{
					Plugin.Fault(site, e);
				}
			});
			return componentInChildren;
		}

		public static RectTransform Rect(GameObject go)
		{
			if (!((Object)(object)go != (Object)null))
			{
				return null;
			}
			Transform transform = go.transform;
			return (RectTransform)(object)((transform is RectTransform) ? transform : null);
		}

		public static void Place(RectTransform rt, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 anchoredPos, Vector2 sizeDelta)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			rt.anchorMin = anchorMin;
			rt.anchorMax = anchorMax;
			rt.pivot = pivot;
			rt.anchoredPosition = anchoredPos;
			rt.sizeDelta = sizeDelta;
		}

		public static string Describe(Transform t, int maxDepth = 4)
		{
			StringBuilder stringBuilder = new StringBuilder();
			Walk(t, 0, maxDepth, stringBuilder);
			if ((Object)(object)t.parent != (Object)null)
			{
				stringBuilder.Append(" container=").Append(((Object)t.parent).name).Append(" layout=")
					.Append((Object)(object)((Component)t.parent).GetComponent<LayoutGroup>() != (Object)null)
					.Append(" children=")
					.Append(t.parent.childCount);
			}
			return stringBuilder.ToString();
		}

		private static void Walk(Transform t, int depth, int maxDepth, StringBuilder sb)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			sb.Append(' ', depth * 2).Append(((Object)t).name).Append(" [");
			Component[] components = ((Component)t).GetComponents<Component>();
			foreach (Component val in components)
			{
				if ((Object)(object)val != (Object)null && !(val is Transform) && !(val is CanvasRenderer))
				{
					sb.Append(((object)val).GetType().Name).Append(' ');
				}
			}
			sb.Append(']');
			RectTransform val2 = (RectTransform)(object)((t is RectTransform) ? t : null);
			if ((Object)(object)val2 != (Object)null)
			{
				object[] obj = new object[7] { val2.anchoredPosition, val2.sizeDelta, null, null, null, null, null };
				Rect rect = val2.rect;
				obj[2] = ((Rect)(ref rect)).width;
				rect = val2.rect;
				obj[3] = ((Rect)(ref rect)).height;
				obj[4] = val2.anchorMin;
				obj[5] = val2.anchorMax;
				obj[6] = val2.pivot;
				sb.Append(string.Format(" pos={0} size={1} rect={2:F0}x{3:F0} aMin={4} aMax={5} pivot={6}", obj));
			}
			TMP_Text component = ((Component)t).GetComponent<TMP_Text>();
			if ((Object)(object)component != (Object)null)
			{
				sb.Append(" text=\"").Append(component.text).Append('"');
			}
			if (!((Component)t).gameObject.activeSelf)
			{
				sb.Append(" INACTIVE");
			}
			sb.Append(" | ");
			for (int j = 0; j < t.childCount; j++)
			{
				if (depth >= maxDepth)
				{
					break;
				}
				Walk(t.GetChild(j), depth + 1, maxDepth, sb);
			}
		}
	}
	internal static class Palette
	{
		public static bool On
		{
			get
			{
				if (ModConfig.ExtendColors != null)
				{
					return ModConfig.ExtendColors.Value;
				}
				return false;
			}
		}

		public static Color[] Extend(Color[] original, int size)
		{
			//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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			int num = ((original != null) ? original.Length : 0);
			if (num >= size)
			{
				return original;
			}
			Color[] array = (Color[])(object)new Color[size];
			for (int i = 0; i < num; i++)
			{
				array[i] = original[i];
			}
			for (int j = num; j < size; j++)
			{
				array[j] = Extra(j - num);
			}
			return array;
		}

		public static Color Extra(int k)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return Color.HSVToRGB(RoomMath.ExtraHue(k), 0.78f, 0.95f);
		}
	}
	[HarmonyPatch(typeof(PlayerBlips), "ColorForIndex")]
	internal static class P_Ui_BlipColor
	{
		private static readonly FieldRef<PlayerBlips, Color[]> Colors = AccessTools.FieldRefAccess<PlayerBlips, Color[]>("playerColors");

		private static void Postfix(PlayerBlips __instance, int i, ref Color __result)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (Palette.On && i >= 0)
				{
					Color[] array = Colors.Invoke(__instance);
					if (array != null && array.Length != 0 && i >= array.Length)
					{
						__result = Palette.Extra(i - array.Length);
					}
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Ui.BlipColor", e);
			}
		}
	}
	[HarmonyPatch(typeof(ShiftCompleteUI), "Awake")]
	internal static class P_Ui_SummaryColors
	{
		private static readonly FieldRef<ShiftCompleteUI, Color[]> Colors = AccessTools.FieldRefAccess<ShiftCompleteUI, Color[]>("_playerColors");

		private static void Postfix(ShiftCompleteUI __instance)
		{
			try
			{
				if (Palette.On)
				{
					Colors.Invoke(__instance) = Palette.Extend(Colors.Invoke(__instance), ModConfig.CapValue);
				}
			}
			catch (Exception e)
			{
				Plugin.Fault("Ui.SummaryColors", e);
			}
		}
	}
}
namespace CrackLargerLobbies.Config
{
	public static class ModConfig
	{
		public const int MinCap = 4;

		public const int MaxCap = 16;

		public static ConfigEntry<int> Cap;

		public static ConfigEntry<bool> ShareAllRooms;

		public static ConfigEntry<float> SpawnOffsetMeters;