Decompiled source of LittleLooneys BiggerLobbies v1.4.0

Mods/ScheduleI.PlayerLimit.dll

Decompiled 16 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using HarmonyLib;
using Il2CppFishNet;
using Il2CppFishNet.Authenticating;
using Il2CppFishNet.Connection;
using Il2CppFishNet.Managing.Server;
using Il2CppFishNet.Managing.Transporting;
using Il2CppFishNet.Object;
using Il2CppFishNet.Transporting;
using Il2CppFishNet.Transporting.Multipass;
using Il2CppFishySteamworks;
using Il2CppFishySteamworks.Server;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Economy;
using Il2CppScheduleOne.GameTime;
using Il2CppScheduleOne.Messaging;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.Networking;
using Il2CppScheduleOne.Persistence;
using Il2CppScheduleOne.Platform;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Quests;
using Il2CppScheduleOne.State;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Multiplayer;
using Il2CppSteamworks;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using ScheduleIPlayerLimit;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "Schedule I Player Limit", "1.4.0", "LittleLooney", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ScheduleI.PlayerLimit")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0")]
[assembly: AssemblyProduct("ScheduleI.PlayerLimit")]
[assembly: AssemblyTitle("ScheduleI.PlayerLimit")]
[assembly: AssemblyVersion("1.4.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace ScheduleIPlayerLimit
{
	[HarmonyPatch(typeof(PlatformAuth), "BeginAuthSession")]
	internal static class TraceSteamAuthentication
	{
		private static void Postfix(EBeginAuthSessionResult __result)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			ModLog.Msg($"[PlayerLimit] Steam BeginAuthSession result: {__result}.");
		}
	}
	[HarmonyPatch(typeof(FishNetSteamAuthenticator), "SetAuthMode")]
	internal static class TraceAuthenticationMode
	{
		private static void Postfix(FishNetSteamAuthenticator __instance)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			ModLog.Msg($"[PlayerLimit] Authentication mode set: {__instance._authMode}.");
		}
	}
	[HarmonyPatch(typeof(FishNetSteamAuthenticator), "OnSteamAuthBroadcast")]
	internal static class TraceAuthenticationTicket
	{
		private static void Prefix(FishNetSteamAuthenticator __instance)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			ModLog.Msg($"[PlayerLimit] Host received authentication ticket; mode={__instance._authMode}.");
		}
	}
	[HarmonyPatch(typeof(FishNetSteamAuthenticator), "SendAuthenticationResponse")]
	internal static class TraceAuthenticationResponse
	{
		private static void Prefix(bool __1)
		{
			ModLog.Msg($"[PlayerLimit] Host sending authentication response: accepted={__1}.");
		}
	}
	[HarmonyPatch(typeof(FishNetSteamAuthenticator), "OnHostAuthenticationResult")]
	internal static class TraceHostAuthentication
	{
		private static void Prefix(bool __1)
		{
			ModLog.Msg($"[PlayerLimit] Host authentication result: accepted={__1}.");
		}
	}
	[HarmonyPatch(typeof(FishNetSteamAuthenticator), "OnResponseBroadcast")]
	internal static class TraceClientAuthenticationResponse
	{
		private static void Prefix()
		{
			ModLog.Msg("[PlayerLimit] Client received authentication response.");
		}
	}
	[HarmonyPatch(typeof(FishNetSteamAuthenticator), "ClientManager_OnClientConnectionState")]
	internal static class TraceClientConnection
	{
		private static void Prefix(ClientConnectionStateArgs __0)
		{
			//IL_0018: 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)
			ModLog.Msg($"Client connection transition: {__0.ConnectionState}.");
		}
	}
	[HarmonyPatch(typeof(FishNetSteamAuthenticator), "ServerManager_OnRemoteConnectionState")]
	internal static class TraceRemoteConnection
	{
		private static void Prefix(RemoteConnectionStateArgs __1)
		{
			//IL_0018: 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)
			ModLog.Msg($"Host remote connection transition: {__1.ConnectionState}.");
		}
	}
	[HarmonyPatch]
	internal static class TraceAuthenticationExceptions
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(FishNetSteamAuthenticator), "OnSteamAuthBroadcast", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(FishNetSteamAuthenticator), "OnResponseBroadcast", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(PlatformAuth), "BeginAuthSession", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(SteamLobbyService), "JoinAsClient", (Type[])null, (Type[])null);
		}

		private static Exception? Finalizer(Exception? __exception, MethodBase __originalMethod)
		{
			if (__exception != null)
			{
				ModLog.Error("Handshake exception in " + __originalMethod.Name, __exception);
			}
			return __exception;
		}
	}
	internal static class DealDiagnostics
	{
		private static readonly Dictionary<IntPtr, float> reported = new Dictionary<IntPtr, float>();

		public static string State(Customer customer)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(96, 7);
			defaultInterpolatedStringHandler.AppendLiteral("customer=");
			NPC nPC = customer.NPC;
			defaultInterpolatedStringHandler.AppendFormatted((nPC != null) ? nPC.BakedGUID : null);
			defaultInterpolatedStringHandler.AppendLiteral(", contract=");
			Contract currentContract = customer.CurrentContract;
			defaultInterpolatedStringHandler.AppendFormatted((currentContract != null) ? new Guid?(((Quest)currentContract).GUID) : ((Guid?)null));
			defaultInterpolatedStringHandler.AppendLiteral(", ");
			defaultInterpolatedStringHandler.AppendLiteral("awaitingDelivery=");
			defaultInterpolatedStringHandler.AppendFormatted(customer.IsAwaitingDelivery);
			defaultInterpolatedStringHandler.AppendLiteral(", offered=");
			defaultInterpolatedStringHandler.AppendFormatted(customer.OfferedContractInfo != null);
			defaultInterpolatedStringHandler.AppendLiteral(", ");
			defaultInterpolatedStringHandler.AppendLiteral("clientInitialized=");
			defaultInterpolatedStringHandler.AppendFormatted(((NetworkBehaviour)customer).IsClientInitialized);
			defaultInterpolatedStringHandler.AppendLiteral(", serverInitialized=");
			defaultInterpolatedStringHandler.AppendFormatted(((NetworkBehaviour)customer).IsServerInitialized);
			defaultInterpolatedStringHandler.AppendLiteral(", time=");
			TimeManager instance = NetworkSingleton<TimeManager>.Instance;
			defaultInterpolatedStringHandler.AppendFormatted((instance != null) ? new int?(instance.CurrentTime) : ((int?)null));
			return defaultInterpolatedStringHandler.ToStringAndClear();
		}

		public static void Gate(Customer customer, string gate)
		{
			if (ModLog.Enabled && (!reported.TryGetValue(((Il2CppObjectBase)customer).Pointer, out var value) || !(Time.realtimeSinceStartup - value < 10f)))
			{
				if (reported.Count > 256)
				{
					reported.Clear();
				}
				reported[((Il2CppObjectBase)customer).Pointer] = Time.realtimeSinceStartup;
				ModLog.Msg($"Deal dialogue gate: {gate}; {State(customer)}.");
			}
		}
	}
	[HarmonyPatch(typeof(Customer), "IsHandoverChoiceValid")]
	internal static class TraceHandoverChoice
	{
		private static void Postfix(Customer __instance, bool __result, string __0)
		{
			DealDiagnostics.Gate(__instance, $"choiceValid={__result}, reason={__0}");
		}
	}
	[HarmonyPatch(typeof(Customer), "IsReadyForHandover")]
	internal static class TraceHandoverReadiness
	{
		private static void Postfix(Customer __instance, bool __result)
		{
			DealDiagnostics.Gate(__instance, $"readyForHandover={__result}");
		}
	}
	[HarmonyPatch]
	internal static class TraceDealFlow
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(typeof(Customer)))
			{
				bool flag;
				switch (declaredMethod.Name)
				{
				case "AcceptContractClicked":
				case "ContractAccepted":
				case "SendCounteroffer":
				case "ProcessHandover":
					flag = true;
					break;
				default:
					flag = false;
					break;
				}
				if (flag || declaredMethod.Name.StartsWith("RpcLogic___ProcessCounterOfferServerSide_", StringComparison.Ordinal) || declaredMethod.Name.StartsWith("RpcLogic___ProcessHandoverServerSide_", StringComparison.Ordinal) || declaredMethod.Name.StartsWith("RpcLogic___ProcessHandoverClient_", StringComparison.Ordinal) || declaredMethod.Name.StartsWith("RpcLogic___ReceiveCustomerData_", StringComparison.Ordinal))
				{
					yield return declaredMethod;
				}
			}
			foreach (MethodInfo declaredMethod2 in AccessTools.GetDeclaredMethods(typeof(QuestManager)))
			{
				if (declaredMethod2.Name.StartsWith("RpcLogic___CreateContract_Networked_", StringComparison.Ordinal))
				{
					yield return declaredMethod2;
				}
			}
		}

		private static void Prefix(object __instance, MethodBase __originalMethod)
		{
			if (ModLog.Enabled)
			{
				Customer val = (Customer)((__instance is Customer) ? __instance : null);
				string value = ((val != null) ? DealDiagnostics.State(val) : "native quest replication");
				ModLog.Msg($"Deal flow: {__originalMethod.Name}; {value}.");
			}
		}

		private static Exception? Finalizer(Exception? __exception, MethodBase __originalMethod)
		{
			if (__exception != null)
			{
				ModLog.Error("Deal flow failed: " + __originalMethod.Name, __exception);
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Customer), "EvaluateCounteroffer")]
	internal static class TraceCounterofferResult
	{
		private static void Postfix(Customer __instance, bool __result)
		{
			ModLog.Msg($"Native counteroffer evaluation: accepted={__result}; {DealDiagnostics.State(__instance)}.");
		}
	}
	internal static class DealSync
	{
		private static readonly Dictionary<string, string> sent = new Dictionary<string, string>();

		private static readonly Dictionary<string, string> outgoing = new Dictionary<string, string>();

		private static readonly Dictionary<string, (string Contract, bool Awaiting)> incoming = new Dictionary<string, (string, bool)>();

		private static readonly Dictionary<ulong, (float Time, IntPtr Connection)> refreshes = new Dictionary<ulong, (float, IntPtr)>();

		private static float nextPoll;

		private static float nextSend;

		private static float nextRequest;

		private static ulong lobbyId;

		private static IEnumerable<Customer> Customers()
		{
			HashSet<IntPtr> seen = new HashSet<IntPtr>();
			List<Customer>[] array = new List<Customer>[2]
			{
				Customer.UnlockedCustomers,
				Customer.LockedCustomers
			};
			foreach (List<Customer> list in array)
			{
				if (list == null)
				{
					continue;
				}
				for (int j = 0; j < list.Count; j++)
				{
					Customer val = list[j];
					if ((Object)(object)val != (Object)null && seen.Add(((Il2CppObjectBase)val).Pointer))
					{
						yield return val;
					}
				}
			}
		}

		public static void Tick()
		{
			Lobby instance = Singleton<Lobby>.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ILobbyService lobbyService = instance._lobbyService;
				obj = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
			}
			SteamLobbyService val = (SteamLobbyService)obj;
			LoadManager instance2 = Singleton<LoadManager>.Instance;
			if (val == null || !val.IsInLobby || instance2 == null || !instance2.IsGameLoaded || instance2.IsLoading)
			{
				Reset();
				return;
			}
			if (lobbyId != val._lobbyID)
			{
				Reset();
				lobbyId = val._lobbyID;
			}
			if (Time.realtimeSinceStartup >= nextPoll)
			{
				nextPoll = Time.realtimeSinceStartup + 2f;
				foreach (Customer item in Customers())
				{
					if (val.IsHost)
					{
						Queue(item, 0uL, force: false);
						continue;
					}
					RepairCallbacks(item);
					Apply(item);
				}
				if (!val.IsHost && Time.realtimeSinceStartup >= nextRequest)
				{
					nextRequest = Time.realtimeSinceStartup + 30f;
					JoinExchange.Send(val, "deal-refresh");
				}
			}
			if (val.IsHost && outgoing.Count > 0 && Time.realtimeSinceStartup >= nextSend)
			{
				nextSend = Time.realtimeSinceStartup + 0.15f;
				KeyValuePair<string, string> keyValuePair = outgoing.First();
				JoinExchange.Send(val, keyValuePair.Value);
				outgoing.Remove(keyValuePair.Key);
			}
		}

		private static void Reset()
		{
			lobbyId = 0uL;
			sent.Clear();
			outgoing.Clear();
			incoming.Clear();
			refreshes.Clear();
			nextPoll = (nextSend = (nextRequest = 0f));
		}

		private static void Queue(Customer customer, ulong target, bool force)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//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)
			NPC nPC = customer.NPC;
			string text = ((nPC != null) ? nPC.BakedGUID : null) ?? "";
			if (!Guid.TryParse(text, out var _))
			{
				return;
			}
			Contract currentContract = customer.CurrentContract;
			string text2 = (((Object)(object)currentContract != (Object)null && (int)((Quest)currentContract).State == 1) ? ((object)((Quest)currentContract).GUID/*cast due to .constrained prefix*/).ToString() : "-");
			bool flag = text2 != "-" && customer.IsAwaitingDelivery;
			string text3 = text2 + "|" + (flag ? "1" : "0");
			if (force || !(sent.TryGetValue(text, out string value) ? (value == text3) : (text2 == "-")))
			{
				if (target == 0L)
				{
					sent[text] = text3;
				}
				outgoing[$"{target}|{text}"] = $"deal|{target}|{text}|{text3}";
			}
		}

		public static void Receive(SteamLobbyService service, ulong sender, string command)
		{
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			if (service.IsHost)
			{
				if ((!(command == "loaded") && !(command == "deal-refresh")) || 1 == 0)
				{
					return;
				}
				LoadManager instance = Singleton<LoadManager>.Instance;
				if (instance == null || !instance.IsGameLoaded || instance.IsLoading || !InstanceFinder.IsServer)
				{
					return;
				}
				Player val = null;
				for (int i = 0; i < Player.PlayerList.Count; i++)
				{
					Player val2 = Player.PlayerList[i];
					if ((Object)(object)val2 != (Object)null && val2.PlayerCode == sender.ToString() && val2.PlayerLoaded && ((NetworkBehaviour)val2).Owner != (NetworkConnection)null && ((NetworkBehaviour)val2).Owner.Authenticated && ((NetworkBehaviour)val2).Owner.IsActive)
					{
						val = val2;
						break;
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				(float, IntPtr) value;
				bool flag = !refreshes.TryGetValue(sender, out value) || value.Item2 != ((Il2CppObjectBase)((NetworkBehaviour)val).Owner).Pointer;
				if (!flag && Time.realtimeSinceStartup - value.Item1 < 15f)
				{
					return;
				}
				refreshes[sender] = (Time.realtimeSinceStartup, ((Il2CppObjectBase)((NetworkBehaviour)val).Owner).Pointer);
				if (flag)
				{
					QuestManager instance2 = NetworkSingleton<QuestManager>.Instance;
					if (instance2 != null)
					{
						((NetworkBehaviour)instance2).OnSpawnServer(((NetworkBehaviour)val).Owner);
					}
					MessagingManager instance3 = NetworkSingleton<MessagingManager>.Instance;
					if (instance3 != null)
					{
						((NetworkBehaviour)instance3).OnSpawnServer(((NetworkBehaviour)val).Owner);
					}
					foreach (Customer item in Customers())
					{
						if (((NetworkBehaviour)item).IsServerInitialized)
						{
							item.ReceiveCustomerData(((NetworkBehaviour)val).Owner, item.GetCustomerData());
						}
					}
					ModLog.Msg($"Deal sync: refreshed native quests, phone messages and customer data for authenticated loaded client {sender}.");
				}
				{
					foreach (Customer item2 in Customers())
					{
						Queue(item2, sender, force: true);
					}
					return;
				}
			}
			if (sender == SteamMatchmaking.GetLobbyOwner(service._lobbySteamID).m_SteamID && SessionPolicy.TryReadDeal(command, SteamUser.GetSteamID().m_SteamID, out string customer, out string contract, out bool awaiting))
			{
				incoming[customer] = (contract, awaiting);
			}
		}

		private static void Apply(Customer customer)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			NPC nPC = customer.NPC;
			string text = ((nPC != null) ? nPC.BakedGUID : null) ?? "";
			if (!incoming.TryGetValue(text, out (string, bool) value))
			{
				return;
			}
			Contract currentContract = customer.CurrentContract;
			bool flag = false;
			if (value.Item1.Length > 0 && ((Object)(object)currentContract == (Object)null || !string.Equals(((object)((Quest)currentContract).GUID/*cast due to .constrained prefix*/).ToString(), value.Item1, StringComparison.OrdinalIgnoreCase)))
			{
				Contract val = null;
				for (int i = 0; i < Quest.ActiveQuests.Count; i++)
				{
					Quest val2 = Quest.ActiveQuests[i];
					if (!((Object)(object)val2 == (Object)null) && string.Equals(((object)val2.GUID/*cast due to .constrained prefix*/).ToString(), value.Item1, StringComparison.OrdinalIgnoreCase))
					{
						Contract val3 = ((Il2CppObjectBase)val2).TryCast<Contract>();
						if ((Object)(object)((val3 != null) ? val3.Customer : null) != (Object)null && (Object)(object)((NetworkBehaviour)customer).NetworkObject != (Object)null && ((Il2CppObjectBase)val3.Customer).Pointer == ((Il2CppObjectBase)((NetworkBehaviour)customer).NetworkObject).Pointer)
						{
							val = val3;
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				customer.AssignContract(val);
				flag = true;
				ModLog.Msg($"Deal sync: restored customer contract link {text}/{value.Item1} from an existing native quest.");
			}
			if (flag || customer.IsAwaitingDelivery != value.Item2)
			{
				customer.SetIsAwaitingDelivery(value.Item2);
				ModLog.Msg($"Deal sync: customer {text} delivery-ready={value.Item2} from host snapshot.");
			}
		}

		public static void RepairCallbacks(Customer customer)
		{
			if (InstanceFinder.IsServer)
			{
				return;
			}
			NPC nPC = customer.NPC;
			object obj;
			if (nPC == null)
			{
				obj = null;
			}
			else
			{
				MSGConversation mSGConversation = nPC.MSGConversation;
				obj = ((mSGConversation != null) ? mSGConversation.currentResponses : null);
			}
			if (obj == null)
			{
				return;
			}
			List<Response> currentResponses = customer.NPC.MSGConversation.currentResponses;
			List<(Response, Action, bool)> list = new List<(Response, Action, bool)>();
			bool flag = false;
			for (int i = 0; i < currentResponses.Count; i++)
			{
				Response val = currentResponses[i];
				if (val == null)
				{
					continue;
				}
				if ((Delegate)(object)val.callback != (Delegate)null)
				{
					list.Add((val, val.callback, val.disableDefaultResponseBehaviour));
					continue;
				}
				bool flag2;
				switch (val.label)
				{
				case "ACCEPT_CONTRACT":
				case "REJECT_CONTRACT":
				case "COUNTEROFFER":
					flag2 = true;
					break;
				default:
					flag2 = false;
					break;
				}
				if (flag2)
				{
					flag = true;
				}
			}
			if (!flag)
			{
				return;
			}
			try
			{
				customer.RpcLogic___SetUpResponseCallbacks_2166136261();
			}
			finally
			{
				foreach (var item in list)
				{
					item.Item1.callback = item.Item2;
					item.Item1.disableDefaultResponseBehaviour = item.Item3;
				}
			}
			ModLog.Msg("Deal sync: repaired missing native phone response callbacks for " + customer.NPC.BakedGUID + ".");
		}
	}
	internal static class HostSession
	{
		private static float nextStart;

		public static bool EnsureReady()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Invalid comparison between Unknown and I4
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Invalid comparison between Unknown and I4
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Invalid comparison between Unknown and I4
			ServerManager serverManager = InstanceFinder.ServerManager;
			TransportManager transportManager = InstanceFinder.TransportManager;
			if ((Object)(object)serverManager == (Object)null || (Object)(object)transportManager == (Object)null)
			{
				return false;
			}
			Multipass obj = ((Il2CppObjectBase)transportManager.Transport).TryCast<Multipass>();
			FishySteamworks val = ((obj != null) ? obj.GetTransport<FishySteamworks>() : null);
			if ((Object)(object)val == (Object)null)
			{
				ModLog.Warning("Cannot prepare host: Steam transport not found.");
				return false;
			}
			Authenticator authenticator = serverManager.Authenticator;
			if ((Object)(object)((authenticator != null) ? ((Il2CppObjectBase)authenticator).TryCast<FishNetSteamAuthenticator>() : null) == (Object)null)
			{
				FishNetSteamAuthenticator val2 = ((Component)serverManager).gameObject.GetComponent<FishNetSteamAuthenticator>();
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = ((Component)serverManager).gameObject.AddComponent<FishNetSteamAuthenticator>();
				}
				serverManager.Authenticator = (Authenticator)(object)val2;
				ModLog.Msg("Installed native Steam authenticator for active host.");
			}
			LocalConnectionState connectionState = ((Transport)val).GetConnectionState(true);
			if ((int)connectionState == 2)
			{
				return true;
			}
			if ((int)connectionState == 1)
			{
				return false;
			}
			if ((int)connectionState != 0 || Time.realtimeSinceStartup < nextStart)
			{
				return false;
			}
			nextStart = Time.realtimeSinceStartup + 5f;
			((Transport)val).SetServerBindAddress(((object)SteamUser.GetSteamID()/*cast due to .constrained prefix*/).ToString(), (IPAddressType)0);
			((Transport)val).SetMaximumClients(Mod.Limit);
			bool flag = ((Transport)val).StartConnection(true);
			ModLog.Msg($"Steam listener start requested: accepted={flag}, state={((Transport)val).GetConnectionState(true)}.");
			if (flag)
			{
				return (int)((Transport)val).GetConnectionState(true) == 2;
			}
			return false;
		}
	}
	internal static class JoinExchange
	{
		private const string Prefix = "LLBL/1|";

		private static ulong lobbyId;

		private static float nextRequest;

		private static int requests;

		private static bool reportedLoaded;

		private static readonly Dictionary<ulong, float> replies = new Dictionary<ulong, float>();

		public static void Send(SteamLobbyService service, string command)
		{
			service.SendMessage("LLBL/1|" + command);
		}

		public static void Tick()
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Invalid comparison between Unknown and I4
			Lobby instance = Singleton<Lobby>.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ILobbyService lobbyService = instance._lobbyService;
				obj = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
			}
			SteamLobbyService val = (SteamLobbyService)obj;
			if (val == null || !val.IsInLobby)
			{
				lobbyId = 0uL;
				return;
			}
			if (lobbyId != val._lobbyID)
			{
				lobbyId = val._lobbyID;
				requests = 0;
				nextRequest = 0f;
				reportedLoaded = false;
				replies.Clear();
			}
			if (val.IsHost)
			{
				return;
			}
			LoadManager instance2 = Singleton<LoadManager>.Instance;
			if (instance2 != null && instance2.IsGameLoaded)
			{
				if (!reportedLoaded)
				{
					reportedLoaded = true;
					val.SendMessage("LLBL/1|loaded");
					ModLog.Msg("Client -> host: game loaded acknowledgement sent.");
				}
			}
			else if ((!((Object)(object)instance2 != (Object)null) || !instance2.IsLoading || (int)instance2.LoadStatus == 5) && !(Time.realtimeSinceStartup < nextRequest))
			{
				LateJoin.Watch(val);
				nextRequest = Time.realtimeSinceStartup + (float)((requests < 12) ? 5 : 15);
				requests++;
				val.SendMessage("LLBL/1|request");
				ModLog.Msg($"Client -> host: readiness request {requests} sent.");
			}
		}

		public static bool Receive(SteamLobbyService service, LobbyChatMsg_t message)
		{
			//IL_0008: 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_002a: 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_004e: Invalid comparison between Unknown and I4
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00b6: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			if (!service.IsInLobby || message.m_ulSteamIDLobby != service._lobbyID)
			{
				return false;
			}
			Il2CppStructArray<byte> val = new Il2CppStructArray<byte>(256L);
			CSteamID val2 = default(CSteamID);
			EChatEntryType val3 = default(EChatEntryType);
			int lobbyChatEntry = SteamMatchmaking.GetLobbyChatEntry(service._lobbySteamID, (int)message.m_iChatID, ref val2, val, 256, ref val3);
			if (lobbyChatEntry <= 0 || lobbyChatEntry > 256 || (int)val3 != 1)
			{
				return false;
			}
			byte[] array = new byte[lobbyChatEntry];
			for (int i = 0; i < lobbyChatEntry; i++)
			{
				array[i] = ((Il2CppArrayBase<byte>)(object)val)[i];
			}
			string text = Encoding.UTF8.GetString(array).TrimEnd('\0');
			if (!text.StartsWith("LLBL/1|", StringComparison.Ordinal))
			{
				return false;
			}
			bool flag = false;
			for (int j = 0; j < SteamMatchmaking.GetNumLobbyMembers(service._lobbySteamID); j++)
			{
				if (SteamMatchmaking.GetLobbyMemberByIndex(service._lobbySteamID, j).m_SteamID == val2.m_SteamID)
				{
					flag = true;
				}
			}
			if (!flag)
			{
				return true;
			}
			string text2 = text;
			int length = "LLBL/1|".Length;
			string text3 = text2.Substring(length, text2.Length - length);
			DealSync.Receive(service, val2.m_SteamID, text3);
			int num;
			if (service.IsHost && val2.m_SteamID != SteamUser.GetSteamID().m_SteamID)
			{
				if (text3 == "loaded")
				{
					ModLog.Msg($"Client {val2.m_SteamID} -> host: game loaded acknowledgement received.");
				}
				if (text3 == "request" && (!replies.TryGetValue(val2.m_SteamID, out var value) || Time.realtimeSinceStartup - value >= 4f))
				{
					replies[val2.m_SteamID] = Time.realtimeSinceStartup;
					ModLog.Msg($"Client {val2.m_SteamID} -> host: readiness request received.");
					LateJoin.Publish(service, notify: false);
					LoadManager instance = Singleton<LoadManager>.Instance;
					if (instance != null && instance.IsGameLoaded)
					{
						LoadManager instance2 = Singleton<LoadManager>.Instance;
						if (instance2 != null && !instance2.IsLoading)
						{
							num = (HostSession.EnsureReady() ? 1 : 0);
							goto IL_0237;
						}
					}
					num = 0;
					goto IL_0237;
				}
			}
			else if (!service.IsHost && val2.m_SteamID == SteamMatchmaking.GetLobbyOwner(service._lobbySteamID).m_SteamID)
			{
				if (text3 == $"reply|{SteamUser.GetSteamID().m_SteamID}|ready")
				{
					ModLog.Msg("Host -> client: ready reply received; checking native loading path.");
					LateJoin.Watch(service);
				}
				else if (text3 == $"reply|{SteamUser.GetSteamID().m_SteamID}|waiting")
				{
					ModLog.Msg("Host -> client: host is still preparing session.");
				}
			}
			goto IL_03c0;
			IL_0237:
			bool flag2 = (byte)num != 0;
			service.SendMessage("LLBL/1|" + $"reply|{val2.m_SteamID}|{(flag2 ? "ready" : "waiting")}");
			ModLog.Msg($"Host -> client {val2.m_SteamID}: {(flag2 ? "ready" : "waiting")} reply sent.");
			goto IL_03c0;
			IL_03c0:
			return true;
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "OnLobbyChatMessage")]
	internal static class ReceiveJoinExchange
	{
		private static bool Prefix(SteamLobbyService __instance, LobbyChatMsg_t __0)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return !JoinExchange.Receive(__instance, __0);
			}
			catch (Exception error)
			{
				ModLog.Error("Lobby-message processing failed", error);
				return true;
			}
		}
	}
	internal static class LateJoin
	{
		private static readonly HashSet<ulong> pending = new HashSet<ulong>();

		private static float nextPoll;

		private static ulong announcedLobby;

		private static bool announcedReady;

		public static void BeginHostLoad()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Lobby instance = Singleton<Lobby>.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ILobbyService lobbyService = instance._lobbyService;
				obj = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
			}
			SteamLobbyService val = (SteamLobbyService)obj;
			if (val != null && val.IsInLobby && val.IsHost)
			{
				announcedReady = false;
				announcedLobby = val._lobbyID;
				SteamMatchmaking.SetLobbyData(val._lobbySteamID, "ready", "false");
				ModLog.Msg("[PlayerLimit] Host began loading; lobby readiness withdrawn.");
			}
		}

		public static void Tick()
		{
			if (!(Time.realtimeSinceStartup < nextPoll))
			{
				nextPoll = Time.realtimeSinceStartup + 1f;
				Lobby instance = Singleton<Lobby>.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					ILobbyService lobbyService = instance._lobbyService;
					obj = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
				}
				SteamLobbyService val = (SteamLobbyService)obj;
				if (val == null || !val.IsInLobby || !val.IsHost)
				{
					announcedReady = false;
					announcedLobby = 0uL;
				}
				else
				{
					Publish(val, notify: false);
				}
			}
		}

		public static void Publish(SteamLobbyService service, bool notify)
		{
			//IL_006c: 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)
			LoadManager instance = Singleton<LoadManager>.Instance;
			if (!service.IsInLobby || !service.IsHost || (Object)(object)instance == (Object)null)
			{
				return;
			}
			if (announcedLobby != service._lobbyID)
			{
				announcedLobby = service._lobbyID;
				announcedReady = false;
			}
			if (!instance.IsGameLoaded || instance.IsLoading)
			{
				announcedReady = false;
				if (service.GetLobbyData("ready") == "true")
				{
					SteamMatchmaking.SetLobbyData(service._lobbySteamID, "ready", "false");
				}
			}
			else
			{
				if (!InstanceFinder.IsServer || !HostSession.EnsureReady())
				{
					return;
				}
				bool flag = service.GetLobbyData("ready") != "true";
				if (flag)
				{
					if (!SteamMatchmaking.SetLobbyData(service._lobbySteamID, "ready", "true"))
					{
						ModLog.Warning("[PlayerLimit] Steam rejected publishing active-session readiness.");
						return;
					}
					ModLog.Msg($"[PlayerLimit] Published active-session readiness for lobby {service._lobbyID}.");
				}
				if (flag || notify || !announcedReady)
				{
					service.SendMessage(Lobby.JoinReadyMessage);
					announcedReady = true;
					ModLog.Msg("[PlayerLimit] Sent native ready message to lobby members.");
				}
			}
		}

		public static void Watch(SteamLobbyService service)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			LoadManager instance = Singleton<LoadManager>.Instance;
			ModLog.Msg($"[PlayerLimit] Lobby entry: id={service._lobbyID}, inLobby={service.IsInLobby}, owner={service.IsHost}, ready={service.GetLobbyData("ready")}, loaded={((instance != null) ? new bool?(instance.IsGameLoaded) : ((bool?)null))}, loading={((instance != null) ? new bool?(instance.IsLoading) : ((bool?)null))}, status={((instance != null) ? new ELoadStatus?(instance.LoadStatus) : ((ELoadStatus?)null))}.");
			if (service.IsInLobby && !service.IsHost && pending.Add(service._lobbyID))
			{
				MelonCoroutines.Start(WaitForHost(service, service._lobbyID));
			}
		}

		private static IEnumerator WaitForHost(SteamLobbyService service, ulong id)
		{
			float nextWaitLog = Time.realtimeSinceStartup + 60f;
			try
			{
				while (service.IsInLobby && service._lobbyID == id && !service.IsHost)
				{
					LoadManager instance = Singleton<LoadManager>.Instance;
					if ((Object)(object)instance != (Object)null && (instance.IsGameLoaded || (instance.IsLoading && (int)instance.LoadStatus != 5)))
					{
						ModLog.Msg($"[PlayerLimit] Client fallback defers to native loader: loaded={instance.IsGameLoaded}, loading={instance.IsLoading}, status={instance.LoadStatus}.");
						break;
					}
					if ((Object)(object)instance != (Object)null && service.GetLobbyData("ready") == "true")
					{
						string sessionConnectionIdentifier = service.GetSessionConnectionIdentifier();
						if (!string.IsNullOrWhiteSpace(sessionConnectionIdentifier))
						{
							ModLog.Msg($"[PlayerLimit] Client fallback starting the native load flow for lobby {id}.");
							service.JoinAsClient(sessionConnectionIdentifier);
							break;
						}
					}
					if (Time.realtimeSinceStartup >= nextWaitLog)
					{
						nextWaitLog = Time.realtimeSinceStartup + 60f;
						ModLog.Msg("[PlayerLimit] Client remains queued for host readiness; waiting continues until loading starts or the lobby is left.");
					}
					yield return null;
				}
			}
			finally
			{
				pending.Remove(id);
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "OnLobbyCreated")]
	internal static class PublishCreatedSession
	{
		private static void Postfix(SteamLobbyService __instance)
		{
			LateJoin.Publish(__instance, notify: false);
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "PlayerEnterOrLeave")]
	internal static class NotifyJoiningPlayer
	{
		private static void Postfix(SteamLobbyService __instance)
		{
			LateJoin.Publish(__instance, notify: true);
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "OnLobbyEntered")]
	internal static class ClientJoinBackup
	{
		private static void Postfix(SteamLobbyService __instance)
		{
			LateJoin.Watch(__instance);
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "JoinAsClient")]
	internal static class TraceClientLoad
	{
		private static string? pendingConnection;

		private static bool Prefix(string __0)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			LoadManager instance = Singleton<LoadManager>.Instance;
			if ((Object)(object)instance != (Object)null && instance.IsLoading && (int)instance.LoadStatus != 5 && pendingConnection == __0)
			{
				ModLog.Msg("[PlayerLimit] Suppressed duplicate JoinAsClient request while native loading is active for the same host.");
				return false;
			}
			pendingConnection = __0;
			ModLog.Msg($"[PlayerLimit] Native JoinAsClient requested: connection={__0}, loaded={((instance != null) ? new bool?(instance.IsGameLoaded) : ((bool?)null))}, loading={((instance != null) ? new bool?(instance.IsLoading) : ((bool?)null))}, status={((instance != null) ? new ELoadStatus?(instance.LoadStatus) : ((ELoadStatus?)null))}.");
			return true;
		}
	}
	[HarmonyPatch(typeof(LoadManager), "StartGame")]
	internal static class WithdrawHostReadiness
	{
		private static void Prefix()
		{
			LateJoin.BeginHostLoad();
		}
	}
	public sealed class Mod : MelonMod
	{
		private static MelonPreferences_Entry<int> limit;

		public static int Limit => Math.Clamp(limit.Value, 4, 32);

		public override void OnUpdate()
		{
			try
			{
				PauseTimeGuard.Tick();
				LateJoin.Tick();
				JoinExchange.Tick();
				ModLog.Observe();
			}
			catch (Exception error)
			{
				ModLog.Error("Mod update failed", error);
			}
			try
			{
				DealSync.Tick();
			}
			catch (Exception error2)
			{
				ModLog.Error("Deal synchronization update failed", error2);
			}
			try
			{
				SleepGuard.Tick();
			}
			catch (Exception error3)
			{
				ModLog.Error("Sleep guard update failed", error3);
			}
		}

		public override void OnInitializeMelon()
		{
			limit = MelonPreferences.CreateCategory("ScheduleIPlayerLimit").CreateEntry<int>("MaxPlayers", 8, "Maximum players", "Includes the host. Restart the game after changing. Allowed range: 4–32.", false, false, (ValueValidator)null, (string)null);
			ModLog.Initialize();
			if (ModLog.Enabled)
			{
				MelonLogger.Msg(ConsoleColor.Magenta, "+----------------------------------------+");
				MelonLogger.Msg(ConsoleColor.Cyan, "|          LittleLooney's Mods           |");
				MelonLogger.Msg(ConsoleColor.Magenta, "|      SCHEDULE I  /  PLAYER LIMIT       |");
				MelonLogger.Msg(ConsoleColor.Cyan, $"|          READY FOR {Limit,2} PLAYERS          |");
				MelonLogger.Msg(ConsoleColor.Magenta, "+----------------------------------------+");
				ModLog.Msg($"Player limit configured to {Limit}. Experimental; test with a fifth client.");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "OnLobbyCreated")]
	internal static class VerifySteamCapacity
	{
		private static void Postfix(SteamLobbyService __instance)
		{
			//IL_000a: 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_0010: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			if (!__instance.IsInLobby)
			{
				return;
			}
			CSteamID lobbySteamID = __instance._lobbySteamID;
			int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(lobbySteamID);
			bool isHost = __instance.IsHost;
			ModLog.Msg($"[PlayerLimit] Lobby {__instance._lobbyID}: capacity before enforcement={lobbyMemberLimit}, local owner={isHost}.");
			if (isHost)
			{
				if (lobbyMemberLimit != Mod.Limit)
				{
					bool value = SteamMatchmaking.SetLobbyMemberLimit(lobbySteamID, Mod.Limit);
					ModLog.Msg($"[PlayerLimit] Lobby {__instance._lobbyID}: SetLobbyMemberLimit({Mod.Limit}) returned {value}.");
					lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(lobbySteamID);
				}
				ModLog.Msg($"[PlayerLimit] Lobby {__instance._lobbyID}: Steam reports lobby capacity: {lobbyMemberLimit}.");
				if (lobbyMemberLimit != Mod.Limit)
				{
					ModLog.Warning($"[PlayerLimit] Requested {Mod.Limit} slots but Steam reports {lobbyMemberLimit}.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(LobbyInterface), "LateUpdate")]
	internal static class LobbyCapacityLabel
	{
		private static void Postfix(LobbyInterface __instance)
		{
			LobbyUi.Refresh(__instance);
		}
	}
	[HarmonyPatch(typeof(LobbyInterface), "Start")]
	internal static class InitialLobbyUi
	{
		private static void Postfix(LobbyInterface __instance)
		{
			LobbyUi.Refresh(__instance);
		}
	}
	[HarmonyPatch(typeof(LobbyInterface), "UpdateUI")]
	internal static class UpdatedLobbyUi
	{
		private static void Postfix(LobbyInterface __instance)
		{
			LobbyUi.Refresh(__instance);
		}
	}
	internal static class LobbyUi
	{
		private static readonly List<LobbyInterface> interfaces = new List<LobbyInterface>();

		public static bool NativePanelVisible => interfaces.Any((LobbyInterface ui) => (Object)(object)ui != (Object)null && ((Behaviour)ui).enabled && (Object)(object)ui.Container != (Object)null && ((Component)ui.Container).gameObject.activeInHierarchy && (Object)(object)ui.LobbyTitle != (Object)null && ((Component)ui.LobbyTitle).gameObject.activeInHierarchy);

		public static void Refresh(LobbyInterface ui)
		{
			interfaces.RemoveAll((LobbyInterface item) => (Object)(object)item == (Object)null);
			if (!interfaces.Contains(ui))
			{
				interfaces.Add(ui);
			}
			int num = Capacity(ui);
			int capacity = ((num > 0) ? num : Mod.Limit);
			Expand(ui, capacity);
			if ((Object)(object)ui.LobbyTitle == (Object)null)
			{
				return;
			}
			string text = ((TMP_Text)ui.LobbyTitle).text;
			if (text != null)
			{
				string text2 = Regex.Replace(text, "(?<=/)\\s*\\d+(?=\\s*\\))", capacity.ToString());
				if (text2 != text)
				{
					((TMP_Text)ui.LobbyTitle).text = text2;
				}
			}
		}

		public static int Capacity(LobbyInterface ui)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			Lobby lobby = ui.Lobby;
			object obj;
			if (lobby == null)
			{
				obj = null;
			}
			else
			{
				ILobbyService lobbyService = lobby._lobbyService;
				obj = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
			}
			SteamLobbyService val = (SteamLobbyService)obj;
			if (val == null || !val.IsInLobby)
			{
				return 0;
			}
			return SteamMatchmaking.GetLobbyMemberLimit(val._lobbySteamID);
		}

		public static void Expand(LobbyInterface ui, int capacity)
		{
			Il2CppReferenceArray<RectTransform> playerSlots = ui.PlayerSlots;
			if (playerSlots == null || ((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length == 0 || capacity <= ((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length || capacity > 32)
			{
				return;
			}
			RectTransform val = ((Il2CppArrayBase<RectTransform>)(object)playerSlots)[((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length - 1];
			if (!((Object)(object)val == (Object)null))
			{
				Il2CppReferenceArray<RectTransform> val2 = new Il2CppReferenceArray<RectTransform>((long)capacity);
				for (int i = 0; i < ((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length; i++)
				{
					((Il2CppArrayBase<RectTransform>)(object)val2)[i] = ((Il2CppArrayBase<RectTransform>)(object)playerSlots)[i];
				}
				for (int j = ((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length; j < capacity; j++)
				{
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Transform)val).parent);
					((Object)val3).name = $"PlayerLimitSlot_{j}";
					val3.SetActive(false);
					((Il2CppArrayBase<RectTransform>)(object)val2)[j] = val3.GetComponent<RectTransform>();
				}
				ui.PlayerSlots = val2;
				GridLayoutGroup component = ((Component)((Transform)val).parent).GetComponent<GridLayoutGroup>();
				if ((Object)(object)component != (Object)null)
				{
					component.constraint = (Constraint)1;
					component.constraintCount = 4;
				}
				ModLog.Msg($"[PlayerLimit] Expanded lobby UI from {((Il2CppArrayBase<RectTransform>)(object)playerSlots).Length} to {capacity} portrait slots.");
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "CreateLobby")]
	internal static class SteamLobbyCapacity
	{
		private static void Prefix(ref int __0)
		{
			__0 = Mod.Limit;
			ModLog.Msg($"[PlayerLimit] Creating Steam lobby with {__0} player slots.");
		}
	}
	[HarmonyPatch(typeof(SteamLobbyService), "UpdateLobbyMembers")]
	internal static class LobbyMemberStorage
	{
		private static void Prefix(SteamLobbyService __instance)
		{
			if (__instance._players == null || ((Il2CppArrayBase<CSteamID>)(object)__instance._players).Length < 32)
			{
				__instance._players = new Il2CppStructArray<CSteamID>(32L);
			}
		}
	}
	[HarmonyPatch(typeof(FishySteamworks), "SetMaximumClients")]
	internal static class TransportCapacity
	{
		private static void Prefix(ref int __0)
		{
			__0 = Mod.Limit;
		}
	}
	[HarmonyPatch(typeof(ServerSocket), "StartConnection")]
	internal static class SocketCapacity
	{
		private static void Prefix(ref int __2)
		{
			__2 = Mod.Limit;
			ModLog.Msg($"[PlayerLimit] Starting server socket with {__2} client slots.");
		}
	}
	[HarmonyPatch(typeof(LobbyInterface), "UpdateButtons")]
	internal static class InviteCapacity
	{
		private static void Postfix(LobbyInterface __instance)
		{
			Lobby lobby = __instance.Lobby;
			if (!((Object)(object)lobby == (Object)null) && !((Object)(object)__instance.InviteButton == (Object)null))
			{
				int num = LobbyUi.Capacity(__instance);
				bool flag = lobby.IsHost && lobby.PlayerCount < ((num > 0) ? num : Mod.Limit);
				((Component)__instance.InviteButton).gameObject.SetActive(flag);
				((Selectable)__instance.InviteButton).interactable = flag;
			}
		}
	}
	[HarmonyPatch(typeof(LobbyInterface), "UpdatePlayers")]
	internal static class SafeLobbyRows
	{
		private static bool Prefix(LobbyInterface __instance)
		{
			Lobby lobby = __instance.Lobby;
			if ((Object)(object)lobby == (Object)null || !lobby.IsInLobby || __instance.PlayerSlots == null)
			{
				return true;
			}
			List<string> lobbyMemberIDs = lobby.GetLobbyMemberIDs();
			if (lobbyMemberIDs == null)
			{
				return true;
			}
			LobbyUi.Expand(__instance, LobbyUi.Capacity(__instance));
			for (int i = 0; i < ((Il2CppArrayBase<RectTransform>)(object)__instance.PlayerSlots).Length; i++)
			{
				if (i < lobbyMemberIDs.Count)
				{
					__instance.DisplayPlayer(i, lobbyMemberIDs[i]);
				}
				else
				{
					__instance.ClearPlayer(i);
				}
			}
			return false;
		}
	}
	internal static class ModLog
	{
		private static MelonPreferences_Entry<bool> enabled = null;

		private static MelonPreferences_Entry<bool> stacks = null;

		private static string lastState = "";

		private static string lastError = "";

		private static float errorTime;

		private static float stateTime;

		private static bool stalled;

		public static bool Enabled => enabled?.Value ?? false;

		public static void Initialize()
		{
			MelonPreferences_Category obj = MelonPreferences.CreateCategory("ScheduleIPlayerLimit");
			enabled = obj.CreateEntry<bool>("EnableLogging", true, "Enable diagnostic logging", (string)null, false, false, (ValueValidator)null, (string)null);
			stacks = obj.CreateEntry<bool>("IncludeStackTraces", true, "Include exception stack traces", (string)null, false, false, (ValueValidator)null, (string)null);
		}

		private static string Context()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			Lobby instance = Singleton<Lobby>.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				ILobbyService lobbyService = instance._lobbyService;
				obj = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
			}
			SteamLobbyService val = (SteamLobbyService)obj;
			LoadManager instance2 = Singleton<LoadManager>.Instance;
			return $"[LLBL lobby={((val != null) ? new ulong?(val._lobbyID) : ((ulong?)null))} role={((val != null && val.IsHost) ? "host" : "client")} state={((instance2 != null) ? new ELoadStatus?(instance2.LoadStatus) : ((ELoadStatus?)null))}]";
		}

		public static void Msg(string message)
		{
			MelonPreferences_Entry<bool> obj = enabled;
			if (obj != null && obj.Value)
			{
				MelonLogger.Msg(Context() + " " + message);
			}
		}

		public static void Warning(string message)
		{
			MelonPreferences_Entry<bool> obj = enabled;
			if (obj != null && obj.Value)
			{
				MelonLogger.Warning(Context() + " " + message);
			}
		}

		public static void Error(string message, Exception error)
		{
			MelonPreferences_Entry<bool> obj = enabled;
			if (obj != null && obj.Value)
			{
				string text = message + error.Message;
				if (!(text == lastError) || !(Time.realtimeSinceStartup - errorTime < 10f))
				{
					lastError = text;
					errorTime = Time.realtimeSinceStartup;
					MelonLogger.Error(message + ": " + (stacks.Value ? error.ToString() : error.Message));
				}
			}
		}

		public static void Observe()
		{
			MelonPreferences_Entry<bool> obj = enabled;
			if (obj == null || !obj.Value)
			{
				return;
			}
			LoadManager instance = Singleton<LoadManager>.Instance;
			string text = $"{Context()} loaded={((instance != null) ? new bool?(instance.IsGameLoaded) : ((bool?)null))} loading={((instance != null) ? new bool?(instance.IsLoading) : ((bool?)null))} server={InstanceFinder.IsServer} client={InstanceFinder.IsClient} timeScale={Time.timeScale}";
			if (text == lastState)
			{
				if (!stalled && instance != null && instance.IsLoading && Time.realtimeSinceStartup - stateTime >= 60f)
				{
					stalled = true;
					Warning("Loading state has not changed for 60 seconds. Compare the host and client handshake logs for this lobby.");
				}
			}
			else
			{
				lastState = text;
				stateTime = Time.realtimeSinceStartup;
				stalled = false;
				MelonLogger.Msg(text);
			}
		}
	}
	[HarmonyPatch]
	internal static class TraceLoadingCalls
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(LoadManager), "StartGame", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(LoadManager), "LoadAsClient", (Type[])null, (Type[])null);
		}

		private static void Prefix(MethodBase __originalMethod)
		{
			ModLog.Msg("Loading entry: " + __originalMethod.Name + ".");
		}

		private static Exception? Finalizer(Exception? __exception, MethodBase __originalMethod)
		{
			if (__exception != null)
			{
				ModLog.Error("Loading exception in " + __originalMethod.Name, __exception);
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "Pause")]
	internal static class ShowPauseInvite
	{
		private static void Postfix(PauseMenu __instance)
		{
			PauseInvites.Refresh(__instance);
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "LateUpdate")]
	internal static class RefreshPauseInvite
	{
		private static void Postfix(PauseMenu __instance)
		{
			if (__instance.IsPaused)
			{
				PauseInvites.Refresh(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "Resume")]
	internal static class HidePauseInvite
	{
		private static void Postfix()
		{
			PauseInvites.Hide();
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "OnDestroy")]
	internal static class CleanupPauseInvite
	{
		private static void Postfix()
		{
			PauseInvites.Cleanup();
		}
	}
	internal static class PauseInvites
	{
		private static Button? button;

		private static TextMeshProUGUI? title;

		private static int canvasId;

		private static bool creating;

		private static bool LocalServerReady()
		{
			LoadManager instance = Singleton<LoadManager>.Instance;
			if (InstanceFinder.IsServer && (Object)(object)instance != (Object)null && instance.IsGameLoaded)
			{
				return !instance.IsLoading;
			}
			return false;
		}

		private static Lobby? ActiveLobby()
		{
			return Singleton<Lobby>.Instance;
		}

		private static SteamLobbyService? HostService(Lobby? lobby)
		{
			if ((Object)(object)lobby == (Object)null || !lobby.IsInLobby)
			{
				return null;
			}
			ILobbyService lobbyService = lobby._lobbyService;
			SteamLobbyService val = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
			if (val == null || !val.IsHost)
			{
				return null;
			}
			return val;
		}

		public static void Refresh(PauseMenu pause)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			Lobby val = ActiveLobby();
			SteamLobbyService val2 = HostService(val);
			if (!LocalServerReady() || (Object)(object)pause.Canvas == (Object)null || (val2 != null && LobbyUi.NativePanelVisible))
			{
				Hide();
				return;
			}
			if ((Object)(object)button == (Object)null || canvasId != ((Object)pause.Canvas).GetInstanceID())
			{
				Create(pause);
			}
			if ((Object)(object)button == (Object)null)
			{
				return;
			}
			((Component)button).gameObject.SetActive(true);
			if (val2 == null)
			{
				((Selectable)button).interactable = !creating && (Object)(object)val != (Object)null;
				if ((Object)(object)title != (Object)null)
				{
					((TMP_Text)title).text = (creating ? "Creating lobby..." : "Invite friends");
				}
				return;
			}
			int lobbyMemberLimit = SteamMatchmaking.GetLobbyMemberLimit(val2._lobbySteamID);
			int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(val2._lobbySteamID);
			((Selectable)button).interactable = !creating && lobbyMemberLimit > numLobbyMembers;
			if ((Object)(object)title != (Object)null)
			{
				((TMP_Text)title).text = $"Lobby ({numLobbyMembers}/{lobbyMemberLimit})";
			}
		}

		private static void Create(PauseMenu pause)
		{
			//IL_000a: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			Cleanup();
			GameObject val = new GameObject("LittleLooneyPauseInvite");
			RectTransform val2 = val.AddComponent<RectTransform>();
			((Transform)val2).SetParent(((Component)pause.Canvas).transform, false);
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(1f, 1f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(1f, 1f);
			val2.anchoredPosition = new Vector2(-32f, -60f);
			val2.sizeDelta = new Vector2(64f, 64f);
			Image val4 = val.AddComponent<Image>();
			((Graphic)val4).color = new Color(0.1f, 0.12f, 0.17f, 0.95f);
			button = val.AddComponent<Button>();
			((Selectable)button).targetGraphic = (Graphic)(object)val4;
			((UnityEvent)button.onClick).AddListener(UnityAction.op_Implicit((Action)Invite));
			TextMeshProUGUI val5 = Label("Plus", (Transform)(object)val2, pause);
			((TMP_Text)val5).text = "+";
			((TMP_Text)val5).fontSize = 52f;
			((TMP_Text)val5).rectTransform.anchorMin = Vector2.zero;
			((TMP_Text)val5).rectTransform.anchorMax = Vector2.one;
			val3 = (((TMP_Text)val5).rectTransform.offsetMin = (((TMP_Text)val5).rectTransform.offsetMax = Vector2.zero));
			title = Label("LobbyCount", (Transform)(object)val2, pause);
			((TMP_Text)title).fontSize = 20f;
			RectTransform rectTransform = ((TMP_Text)title).rectTransform;
			RectTransform rectTransform2 = ((TMP_Text)title).rectTransform;
			((Vector2)(ref val3))..ctor(1f, 1f);
			rectTransform2.anchorMax = val3;
			rectTransform.anchorMin = val3;
			((TMP_Text)title).rectTransform.pivot = new Vector2(1f, 0f);
			((TMP_Text)title).rectTransform.anchoredPosition = new Vector2(0f, 8f);
			((TMP_Text)title).rectTransform.sizeDelta = new Vector2(180f, 30f);
			((TMP_Text)title).alignment = (TextAlignmentOptions)516;
			((Transform)val2).SetAsLastSibling();
			canvasId = ((Object)pause.Canvas).GetInstanceID();
			ModLog.Msg("[PlayerLimit] Pause-menu invite button created. Enabled when the host session is ready and has space.");
		}

		private static TextMeshProUGUI Label(string name, Transform parent, PauseMenu pause)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			((Transform)val.AddComponent<RectTransform>()).SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)pause.CartelNameLabel != (Object)null)
			{
				((TMP_Text)val2).font = ((TMP_Text)pause.CartelNameLabel).font;
			}
			((Graphic)val2).color = Color.white;
			((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private static void Invite()
		{
			if (!LocalServerReady() || creating)
			{
				return;
			}
			Lobby val = ActiveLobby();
			SteamLobbyService val2 = HostService(val);
			if (!((Object)(object)val == (Object)null))
			{
				if (val2 == null)
				{
					creating = true;
					MelonCoroutines.Start(CreateAndInvite(val));
				}
				else
				{
					Open(val2, val);
				}
			}
		}

		private static IEnumerator CreateAndInvite(Lobby lobby)
		{
			try
			{
				ModLog.Msg("[PlayerLimit] Creating a Steam lobby for the loaded local server.");
				lobby.CreateLobby();
				float deadline = Time.realtimeSinceStartup + 15f;
				SteamLobbyService val;
				while ((val = HostService(lobby)) == null && Time.realtimeSinceStartup < deadline && LocalServerReady())
				{
					yield return null;
				}
				if (val != null && LocalServerReady())
				{
					Open(val, lobby);
				}
				else
				{
					ModLog.Warning("[PlayerLimit] Host lobby creation did not complete within 15 seconds.");
				}
			}
			finally
			{
				creating = false;
			}
		}

		private static void Open(SteamLobbyService service, Lobby lobby)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (!HostSession.EnsureReady())
			{
				ModLog.Warning("Steam listener is not ready yet; wait a moment and click invite again.");
				return;
			}
			LateJoin.Publish(service, notify: false);
			ModLog.Msg($"[PlayerLimit] Active-session readiness reported by game: {lobby.IsSessionReadyForClient()}.");
			CSteamID lobbySteamID = service._lobbySteamID;
			if (SteamMatchmaking.GetNumLobbyMembers(lobbySteamID) < SteamMatchmaking.GetLobbyMemberLimit(lobbySteamID))
			{
				if (!SteamMatchmaking.SetLobbyJoinable(lobbySteamID, true))
				{
					ModLog.Warning("[PlayerLimit] Steam did not accept making the host lobby joinable.");
					return;
				}
				ModLog.Msg($"[PlayerLimit] Opening active-session invite dialog for lobby {service._lobbyID}.");
				service.OpenInviteUI();
			}
		}

		public static void Hide()
		{
			if ((Object)(object)button != (Object)null)
			{
				((Component)button).gameObject.SetActive(false);
			}
		}

		public static void Cleanup()
		{
			if ((Object)(object)button != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)button).gameObject);
			}
			button = null;
			title = null;
			canvasId = 0;
		}
	}
	internal static class PauseTimeGuard
	{
		private static bool ownsFreeze;

		private static float previousScale;

		public static void Capture(float before)
		{
			if (!(before <= 0f) && Time.timeScale == 0f)
			{
				previousScale = before;
				ownsFreeze = true;
				ModLog.Msg($"Pause menu froze simulation: timeScale={Time.timeScale}, previous={before}.");
			}
		}

		public static void Tick()
		{
			if (!ownsFreeze)
			{
				return;
			}
			LoadManager instance = Singleton<LoadManager>.Instance;
			if ((Object)(object)instance == (Object)null || !instance.IsGameLoaded || instance.IsLoading)
			{
				Clear();
				return;
			}
			Lobby instance2 = Singleton<Lobby>.Instance;
			object obj;
			if (instance2 == null)
			{
				obj = null;
			}
			else
			{
				ILobbyService lobbyService = instance2._lobbyService;
				obj = ((lobbyService != null) ? ((Il2CppObjectBase)lobbyService).TryCast<SteamLobbyService>() : null);
			}
			SteamLobbyService val = (SteamLobbyService)obj;
			if (val != null && val.IsInLobby && val.IsHost && InstanceFinder.IsServer)
			{
				Restore("Solo pause transitioned to multiplayer lobby");
			}
		}

		public static void Resumed()
		{
			if (ownsFreeze)
			{
				Restore("Pause menu resumed");
			}
		}

		private static void Restore(string reason)
		{
			if (Time.timeScale == 0f)
			{
				Time.timeScale = previousScale;
				ModLog.Msg($"{reason}: restored pause-owned timeScale to {previousScale}.");
			}
			Clear();
		}

		public static void Clear()
		{
			ownsFreeze = false;
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "Pause")]
	internal static class CapturePauseTime
	{
		private static void Prefix(out float __state)
		{
			__state = Time.timeScale;
		}

		private static void Postfix(float __state)
		{
			PauseTimeGuard.Capture(__state);
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "Resume")]
	internal static class RestorePauseTime
	{
		private static void Postfix()
		{
			PauseTimeGuard.Resumed();
		}
	}
	[HarmonyPatch(typeof(PauseMenu), "OnDestroy")]
	internal static class ClearPauseTime
	{
		private static void Postfix()
		{
			PauseTimeGuard.Clear();
		}
	}
	internal static class SessionPolicy
	{
		public static bool SleepHours(int time)
		{
			if (time < 1800 || time >= 2400)
			{
				if (time >= 0)
				{
					return time <= 400;
				}
				return false;
			}
			return true;
		}

		public static bool TryReadDeal(string text, ulong localUser, out string customer, out string contract, out bool awaiting)
		{
			customer = (contract = "");
			awaiting = false;
			string[] array = text.Split('|');
			ulong result;
			Guid result2;
			bool flag = array.Length != 5 || array[0] != "deal" || !ulong.TryParse(array[1], out result) || (result != 0L && result != localUser) || !Guid.TryParse(array[2], out result2) || (array[3] != "-" && !Guid.TryParse(array[3], out result2));
			if (!flag)
			{
				string text2 = array[4];
				bool flag2 = ((text2 == "0" || text2 == "1") ? true : false);
				flag = !flag2;
			}
			if (flag)
			{
				return false;
			}
			customer = array[2];
			contract = ((array[3] == "-") ? "" : array[3]);
			awaiting = array[4] == "1";
			if (awaiting)
			{
				return contract.Length > 0;
			}
			return true;
		}
	}
	internal static class SleepGuard
	{
		private static IntPtr controller;

		private static EPhase phase;

		private static bool observedSleep;

		private static float phaseSince;

		private static float nextPoll;

		private static float nextWarning;

		public static bool Allowed()
		{
			TimeManager instance = NetworkSingleton<TimeManager>.Instance;
			if (!GameManager.IS_TUTORIAL && !((Object)(object)instance == (Object)null))
			{
				return SessionPolicy.SleepHours(instance.CurrentTime);
			}
			return true;
		}

		public static void ClearReady(SleepController sleep)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			if (!InstanceFinder.IsServer)
			{
				return;
			}
			LoadManager instance = Singleton<LoadManager>.Instance;
			if (instance == null || !instance.IsGameLoaded)
			{
				return;
			}
			int num = 0;
			for (int i = 0; i < Player.PlayerList.Count; i++)
			{
				Player val = Player.PlayerList[i];
				if (!((Object)(object)val == (Object)null) && val.IsReadyToSleep)
				{
					val.IsReadyToSleep = false;
					num++;
				}
			}
			if (num > 0)
			{
				ModLog.Msg($"Sleep guard: cleared {num} authoritative ready flags after wake; phase={sleep.CurrentPhase}.");
			}
		}

		public static void Tick()
		{
			//IL_00a9: 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_007a: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			if (Time.realtimeSinceStartup < nextPoll)
			{
				return;
			}
			nextPoll = Time.realtimeSinceStartup + 1f;
			SleepController instance = NetworkSingleton<SleepController>.Instance;
			LoadManager instance2 = Singleton<LoadManager>.Instance;
			if ((Object)(object)instance == (Object)null || instance2 == null || !instance2.IsGameLoaded || instance2.IsLoading)
			{
				controller = IntPtr.Zero;
				observedSleep = false;
				return;
			}
			if (controller != ((Il2CppObjectBase)instance).Pointer)
			{
				controller = ((Il2CppObjectBase)instance).Pointer;
				phase = instance.CurrentPhase;
				observedSleep = instance.IsSleepInProgress;
				phaseSince = Time.realtimeSinceStartup;
				nextWarning = phaseSince + 90f;
			}
			if (phase != instance.CurrentPhase)
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(73, 7);
				defaultInterpolatedStringHandler.AppendLiteral("Sleep phase: ");
				defaultInterpolatedStringHandler.AppendFormatted<EPhase>(phase);
				defaultInterpolatedStringHandler.AppendLiteral(" -> ");
				defaultInterpolatedStringHandler.AppendFormatted<EPhase>(instance.CurrentPhase);
				defaultInterpolatedStringHandler.AppendLiteral("; time=");
				TimeManager instance3 = NetworkSingleton<TimeManager>.Instance;
				defaultInterpolatedStringHandler.AppendFormatted((instance3 != null) ? new int?(instance3.CurrentTime) : ((int?)null));
				defaultInterpolatedStringHandler.AppendLiteral(", hostReady=");
				defaultInterpolatedStringHandler.AppendFormatted(instance.IsHostReadyToProceed);
				defaultInterpolatedStringHandler.AppendLiteral(", sleepingState=");
				MonoStateMachine sleepingState = instance.SleepingState;
				defaultInterpolatedStringHandler.AppendFormatted((sleepingState != null) ? new bool?(((MonoState)sleepingState).IsActive) : ((bool?)null));
				defaultInterpolatedStringHandler.AppendLiteral(", canMove=");
				PlayerMovement instance4 = PlayerSingleton<PlayerMovement>.Instance;
				defaultInterpolatedStringHandler.AppendFormatted((instance4 != null) ? new bool?(instance4.CanMove) : ((bool?)null));
				defaultInterpolatedStringHandler.AppendLiteral(", canLook=");
				PlayerCamera instance5 = PlayerSingleton<PlayerCamera>.Instance;
				defaultInterpolatedStringHandler.AppendFormatted((instance5 != null) ? new bool?(instance5.CanLook) : ((bool?)null));
				defaultInterpolatedStringHandler.AppendLiteral(".");
				ModLog.Msg(defaultInterpolatedStringHandler.ToStringAndClear());
				phase = instance.CurrentPhase;
				phaseSince = Time.realtimeSinceStartup;
				nextWarning = phaseSince + 90f;
			}
			if (observedSleep && !instance.IsSleepInProgress)
			{
				ClearReady(instance);
				MonoStateMachine sleepingState2 = instance.SleepingState;
				if (sleepingState2 != null && ((MonoState)sleepingState2).IsActive)
				{
					((MonoState)instance.SleepingState).RemoveFromDefaultParent();
					ModLog.Warning("Sleep guard: removed the still-active sleeping state after the native sleep phase ended.");
				}
			}
			observedSleep = instance.IsSleepInProgress;
			if (observedSleep && ModLog.Enabled && Time.realtimeSinceStartup >= nextWarning)
			{
				nextWarning = Time.realtimeSinceStartup + 60f;
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(99, 7);
				defaultInterpolatedStringHandler.AppendLiteral("Sleep has stayed in ");
				defaultInterpolatedStringHandler.AppendFormatted<EPhase>(phase);
				defaultInterpolatedStringHandler.AppendLiteral(" for ");
				defaultInterpolatedStringHandler.AppendFormatted(Time.realtimeSinceStartup - phaseSince, "F0");
				defaultInterpolatedStringHandler.AppendLiteral("s; timeScale=");
				defaultInterpolatedStringHandler.AppendFormatted(Time.timeScale);
				defaultInterpolatedStringHandler.AppendLiteral(", hostReady=");
				defaultInterpolatedStringHandler.AppendFormatted(instance.IsHostReadyToProceed);
				defaultInterpolatedStringHandler.AppendLiteral(", sleepingState=");
				MonoStateMachine sleepingState3 = instance.SleepingState;
				defaultInterpolatedStringHandler.AppendFormatted((sleepingState3 != null) ? new bool?(((MonoState)sleepingState3).IsActive) : ((bool?)null));
				defaultInterpolatedStringHandler.AppendLiteral(". Pending events: ");
				defaultInterpolatedStringHandler.AppendFormatted(Events(instance.sleepEventQueue));
				defaultInterpolatedStringHandler.AppendLiteral("; post-sleep: ");
				defaultInterpolatedStringHandler.AppendFormatted(Events(instance.postSleepEventQueue));
				defaultInterpolatedStringHandler.AppendLiteral(".");
				ModLog.Warning(defaultInterpolatedStringHandler.ToStringAndClear());
			}
		}

		private static string Events(List<ISleepEvent> events)
		{
			if (events == null)
			{
				return "none";
			}
			List<string> list = new List<string>();
			for (int i = 0; i < events.Count; i++)
			{
				ISleepEvent val = events[i];
				if (val != null)
				{
					list.Add($"{((object)((Il2CppObjectBase)val).TryCast<Object>())?.GetType().FullName}(running={val.IsInProgress})");
				}
			}
			return string.Join(", ", list.Take(12));
		}
	}
	[HarmonyPatch(typeof(SleepController), "CheckSleepStart")]
	internal static class CheckSleepHours
	{
		private static bool Prefix(SleepController __instance)
		{
			if (InstanceFinder.IsServer && !__instance.IsSleepInProgress)
			{
				return SleepGuard.Allowed();
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(SleepController), "RpcLogic___StartSleep_2166136261")]
	internal static class PreventDuplicateSleep
	{
		private static bool Prefix(SleepController __instance)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!__instance.IsSleepInProgress)
			{
				return true;
			}
			ModLog.Warning($"Suppressed duplicate sleep start while phase={__instance.CurrentPhase}.");
			return false;
		}
	}
	[HarmonyPatch]
	internal static class SleepMenuHours
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(SleepMenu), "OpenMenu", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(SleepMenu), "SleepButtonPressed", (Type[])null, (Type[])null);
		}

		private static bool Prefix(SleepMenu __instance)
		{
			if (SleepGuard.Allowed())
			{
				return true;
			}
			DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(55, 1);
			defaultInterpolatedStringHandler.AppendLiteral("Sleep guard: ignored morning/daytime sleep request at ");
			TimeManager instance = NetworkSingleton<TimeManager>.Instance;
			defaultInterpolatedStringHandler.AppendFormatted((instance != null) ? new int?(instance.CurrentTime) : ((int?)null));
			defaultInterpolatedStringHandler.AppendLiteral(".");
			ModLog.Msg(defaultInterpolatedStringHandler.ToStringAndClear());
			if (__instance.IsMenuOpen)
			{
				MonoState menuState = __instance.MenuState;
				if (menuState != null)
				{
					menuState.RemoveFromDefaultParent();
				}
				if (__instance.IsMenuOpen)
				{
					__instance.OnMenuClosed();
				}
				Player local = Player.Local;
				if (local != null)
				{
					local.SetReadyToSleep(false);
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class TraceSleepCoroutines
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			Type[] nestedTypes = typeof(SleepController).GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
			for (int i = 0; i < nestedTypes.Length; i++)
			{
				MethodInfo methodInfo = AccessTools.Method(nestedTypes[i], "MoveNext", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					yield return methodInfo;
				}
			}
		}

		private static Exception? Finalizer(Exception? __exception, MethodBase __originalMethod)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (__exception != null)
			{
				DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(32, 2);
				defaultInterpolatedStringHandler.AppendLiteral("Sleep coroutine failed: ");
				defaultInterpolatedStringHandler.AppendFormatted(__originalMethod.DeclaringType?.Name);
				defaultInterpolatedStringHandler.AppendLiteral("; phase=");
				SleepController instance = NetworkSingleton<SleepController>.Instance;
				defaultInterpolatedStringHandler.AppendFormatted((instance != null) ? new EPhase?(instance.CurrentPhase) : ((EPhase?)null));
				ModLog.Error(defaultInterpolatedStringHandler.ToStringAndClear(), __exception);
			}
			return __exception;
		}
	}
}