Decompiled source of RoundsReconnect v0.1.4

RoundsReconnect.dll

Decompiled 4 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using InControl;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace RoundsReconnect
{
	internal sealed class ReconnectCallbacks : MonoBehaviourPunCallbacks
	{
		public override void OnJoinedRoom()
		{
			ReconnectManager.Instance?.OnJoinedRoom();
			((MonoBehaviourPunCallbacks)this).OnJoinedRoom();
		}

		public override void OnPlayerEnteredRoom(Player newPlayer)
		{
			ReconnectManager.Instance?.OnPlayerEnteredRoom(newPlayer);
			((MonoBehaviourPunCallbacks)this).OnPlayerEnteredRoom(newPlayer);
		}

		public override void OnPlayerLeftRoom(Player otherPlayer)
		{
			ReconnectManager.Instance?.OnPlayerLeftRoom(otherPlayer);
			((MonoBehaviourPunCallbacks)this).OnPlayerLeftRoom(otherPlayer);
		}
	}
	internal sealed class ReconnectManager : MonoBehaviour
	{
		internal const string PlayerSteamKey = "rr.steam";

		internal const string RoomSlotsKey = "rr.slots";

		internal const string RoomGameActiveKey = "rr.active";

		private string localSteamId;

		internal static ReconnectManager Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)this);
		}

		internal void PublishLocalSteamId()
		{
			if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null)
			{
				localSteamId = SteamIdentity.LocalSteamId();
				SetPlayerProperty(PhotonNetwork.LocalPlayer, "rr.steam", localSteamId);
			}
		}

		internal void SetGameActive(bool active)
		{
			if (IsPrivateRwfRoom() && PhotonNetwork.IsMasterClient)
			{
				SetRoomProperty("rr.active", active);
				if (active)
				{
					RefreshSlotsFromLivePlayers();
				}
			}
		}

		internal bool IsGameActive()
		{
			if (PhotonNetwork.CurrentRoom != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"rr.active", out object value) && value is bool)
			{
				return (bool)value;
			}
			return false;
		}

		internal bool IsPrivateRwfRoom()
		{
			if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom != null && !PhotonNetwork.OfflineMode)
			{
				return !PhotonNetwork.CurrentRoom.IsVisible;
			}
			return false;
		}

		internal void OnJoinedRoom()
		{
			PublishLocalSteamId();
			RequestClaimIfNeeded();
		}

		internal void OnPlayerEnteredRoom(Player player)
		{
			if (IsPrivateRwfRoom() && PhotonNetwork.IsMasterClient && player != null)
			{
				ResolveClaims();
			}
		}

		internal void OnPlayerLeftRoom(Player player)
		{
			if (!IsPrivateRwfRoom() || !PhotonNetwork.IsMasterClient || player == null || player.IsMasterClient)
			{
				return;
			}
			List<SlotRecord> slots = GetSlots();
			bool flag = false;
			foreach (SlotRecord item in slots.Where((SlotRecord slot) => slot.OwnerActor == player.ActorNumber))
			{
				item.State = SlotState.Abandoned;
				item.ClaimActor = 0;
				flag = true;
			}
			if (flag)
			{
				SetSlots(slots);
				RoundsReconnectPlugin.Log.LogInfo((object)$"Actor {player.ActorNumber} left; slot marked abandoned");
			}
		}

		internal void BeforeCardPick(int pickerId)
		{
			if (IsPrivateRwfRoom())
			{
				PublishLocalSteamId();
				RequestClaimIfNeeded();
				if (PhotonNetwork.IsMasterClient)
				{
					RefreshSlotsFromLivePlayers();
					MarkDisconnectedOwners();
					ResolveClaims();
					TransferClaimIfPicker(pickerId);
					ConvertClaimableSlotsToBots();
				}
				ApplyRoomSlotsToLocalObjects();
			}
		}

		internal void MarkLocalSlotsAbandonedBeforeLeave()
		{
			if (!IsPrivateRwfRoom() || PhotonNetwork.IsMasterClient || !IsGameActive())
			{
				return;
			}
			PublishLocalSteamId();
			List<SlotRecord> slots = GetSlots();
			bool flag = false;
			foreach (Player player in LivePlayers())
			{
				if (!((Object)(object)player.data == (Object)null) && !((Object)(object)player.data.view == (Object)null) && player.data.view.OwnerActorNr == PhotonNetwork.LocalPlayer.ActorNumber)
				{
					SlotRecord slotRecord = slots.FirstOrDefault((SlotRecord candidate) => candidate.PlayerId == player.playerID);
					if (slotRecord == null)
					{
						slotRecord = SlotFromPlayer(player);
						slots.Add(slotRecord);
					}
					slotRecord.SteamId = localSteamId;
					slotRecord.OwnerActor = PhotonNetwork.LocalPlayer.ActorNumber;
					slotRecord.State = SlotState.Abandoned;
					slotRecord.ClaimActor = 0;
					flag = true;
				}
			}
			if (flag)
			{
				SetSlots(slots);
				RoundsReconnectPlugin.Log.LogInfo((object)"Local player slot marked abandoned before leave");
			}
		}

		internal bool ShouldBlockLobbyReady()
		{
			if (!IsPrivateRwfRoom() || !IsGameActive())
			{
				return false;
			}
			string steamId = localSteamId ?? SteamIdentity.LocalSteamId();
			return GetSlots().Any((SlotRecord slot) => slot.IsClaimable && slot.SteamId == steamId);
		}

		private void RefreshSlotsFromLivePlayers()
		{
			if (!IsPrivateRwfRoom() || !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			List<SlotRecord> slots = GetSlots();
			bool flag = false;
			foreach (Player player in LivePlayers())
			{
				SlotRecord slotRecord = slots.FirstOrDefault((SlotRecord candidate) => candidate.PlayerId == player.playerID);
				if (slotRecord == null)
				{
					slots.Add(SlotFromPlayer(player));
					flag = true;
				}
				else if (slotRecord.State == SlotState.Human)
				{
					slotRecord.TeamId = player.teamID;
					slotRecord.ViewId = player.data.view.ViewID;
					slotRecord.OwnerActor = player.data.view.OwnerActorNr;
					flag = true;
				}
			}
			if (flag)
			{
				SetSlots(slots);
			}
		}

		private void MarkDisconnectedOwners()
		{
			List<SlotRecord> slots = GetSlots();
			bool flag = false;
			foreach (SlotRecord item in slots.Where((SlotRecord slot) => slot.State == SlotState.Human))
			{
				if (!PhotonNetwork.CurrentRoom.Players.ContainsKey(item.OwnerActor))
				{
					item.State = SlotState.Abandoned;
					item.ClaimActor = 0;
					flag = true;
				}
			}
			if (flag)
			{
				SetSlots(slots);
			}
		}

		private void ResolveClaims()
		{
			List<SlotRecord> slots = GetSlots();
			bool flag = false;
			foreach (Player value in PhotonNetwork.CurrentRoom.Players.Values)
			{
				string steamId = GetPlayerProperty<string>(value, "rr.steam");
				if (!string.IsNullOrEmpty(steamId))
				{
					SlotRecord slotRecord = slots.FirstOrDefault((SlotRecord candidate) => candidate.IsClaimable && candidate.SteamId == steamId);
					if (slotRecord != null && slotRecord.ClaimActor != value.ActorNumber)
					{
						slotRecord.ClaimActor = value.ActorNumber;
						flag = true;
						RoundsReconnectPlugin.Log.LogInfo((object)$"Actor {value.ActorNumber} queued to reclaim player {slotRecord.PlayerId}");
					}
				}
			}
			if (flag)
			{
				SetSlots(slots);
			}
		}

		private void TransferClaimIfPicker(int pickerId)
		{
			List<SlotRecord> slots = GetSlots();
			SlotRecord slotRecord = slots.FirstOrDefault((SlotRecord candidate) => candidate.PlayerId == pickerId && candidate.ClaimActor > 0);
			if (slotRecord != null && PhotonNetwork.CurrentRoom.Players.ContainsKey(slotRecord.ClaimActor))
			{
				Player val = FindPlayer(slotRecord.PlayerId);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.data == (Object)null) && !((Object)(object)val.data.view == (Object)null))
				{
					TryTransferOwnership(val, slotRecord.ClaimActor);
					slotRecord.OwnerActor = slotRecord.ClaimActor;
					slotRecord.ClaimActor = 0;
					slotRecord.State = SlotState.Human;
					SetSlots(slots);
					RoundsReconnectPlugin.Log.LogInfo((object)$"Player {slotRecord.PlayerId} reclaimed by actor {slotRecord.OwnerActor}");
				}
			}
		}

		private void ConvertClaimableSlotsToBots()
		{
			bool flag = false;
			List<SlotRecord> slots = GetSlots();
			foreach (SlotRecord item in slots.Where((SlotRecord candidate) => candidate.IsClaimable))
			{
				Player val = FindPlayer(item.PlayerId);
				if (!((Object)(object)val == (Object)null))
				{
					RoundsWithBotsBridge.ConvertToBot(val);
					if (item.State != SlotState.Bot)
					{
						item.State = SlotState.Bot;
						flag = true;
					}
				}
			}
			if (flag)
			{
				SetSlots(slots);
				RoundsWithBotsBridge.RefreshBotPickerList();
			}
		}

		private void ApplyRoomSlotsToLocalObjects()
		{
			foreach (SlotRecord slot in GetSlots())
			{
				Player val = FindPlayer(slot.PlayerId);
				if (!((Object)(object)val == (Object)null))
				{
					if (slot.State == SlotState.Bot || slot.State == SlotState.Abandoned)
					{
						RoundsWithBotsBridge.ConvertToBot(val);
					}
					else if (slot.State == SlotState.Human && slot.OwnerActor == PhotonNetwork.LocalPlayer.ActorNumber)
					{
						RoundsWithBotsBridge.ConvertToHuman(val);
					}
				}
			}
		}

		private void RequestClaimIfNeeded()
		{
			if (IsPrivateRwfRoom() && IsGameActive())
			{
				string steamId = localSteamId ?? SteamIdentity.LocalSteamId();
				if (GetSlots().Any((SlotRecord slot) => slot.IsClaimable && slot.SteamId == steamId))
				{
					SetPlayerProperty(PhotonNetwork.LocalPlayer, "rr.steam", steamId);
				}
			}
		}

		private SlotRecord SlotFromPlayer(Player player)
		{
			int num = (((Object)(object)player.data?.view != (Object)null) ? player.data.view.OwnerActorNr : 0);
			return new SlotRecord
			{
				SteamId = (GetPlayerProperty<string>(PhotonNetwork.CurrentRoom.GetPlayer(num), "rr.steam") ?? string.Empty),
				PlayerId = player.playerID,
				TeamId = player.teamID,
				OwnerActor = num,
				ClaimActor = 0,
				ViewId = (((Object)(object)player.data?.view != (Object)null) ? player.data.view.ViewID : 0),
				State = SlotState.Human
			};
		}

		private static void TryTransferOwnership(Player player, int actorNumber)
		{
			try
			{
				player.data.view.TransferOwnership(actorNumber);
			}
			catch (Exception ex)
			{
				RoundsReconnectPlugin.Log.LogWarning((object)$"Ownership transfer failed for player {player.playerID}: {ex.Message}");
			}
		}

		private static Player FindPlayer(int playerId)
		{
			return PlayerManager.instance?.players?.FirstOrDefault((Func<Player, bool>)((Player player) => (Object)(object)player != (Object)null && player.playerID == playerId));
		}

		private static IEnumerable<Player> LivePlayers()
		{
			return PlayerManager.instance?.players?.Where((Player player) => (Object)(object)player != (Object)null) ?? Enumerable.Empty<Player>();
		}

		private static List<SlotRecord> GetSlots()
		{
			if (PhotonNetwork.CurrentRoom == null || !((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"rr.slots", out object value))
			{
				return new List<SlotRecord>();
			}
			return SlotRecord.DeserializeMany(value as string);
		}

		private static void SetSlots(IEnumerable<SlotRecord> slots)
		{
			SetRoomProperty("rr.slots", SlotRecord.SerializeMany(slots));
		}

		private static void SetRoomProperty(string key, object value)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0021: Expected O, but got Unknown
			if (PhotonNetwork.CurrentRoom != null)
			{
				Room currentRoom = PhotonNetwork.CurrentRoom;
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)key, value);
				currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			}
		}

		private static void SetPlayerProperty(Player player, string key, object value)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Expected O, but got Unknown
			if (player != null)
			{
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)key, value);
				player.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			}
		}

		private static T GetPlayerProperty<T>(Player player, string key)
		{
			if (player == null)
			{
				return default(T);
			}
			if (!((Dictionary<object, object>)(object)player.CustomProperties).TryGetValue((object)key, out object value) || !(value is T))
			{
				return default(T);
			}
			return (T)value;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.joema.rounds.roundsreconnect", "Rounds Reconnect", "0.1.0")]
	[BepInProcess("Rounds.exe")]
	public sealed class RoundsReconnectPlugin : BaseUnityPlugin
	{
		public const string ModId = "com.joema.rounds.roundsreconnect";

		public const string ModName = "Rounds Reconnect";

		public const string Version = "0.1.0";

		internal static RoundsReconnectPlugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			new Harmony("com.joema.rounds.roundsreconnect").PatchAll();
			((Component)this).gameObject.AddComponent<ReconnectCallbacks>();
			((Component)this).gameObject.AddComponent<ReconnectManager>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Rounds Reconnect 0.1.0 loaded");
		}
	}
	internal static class RoundsWithBotsBridge
	{
		private static Type characterDataExtensionType;

		private static Type botManagerType;

		public static void SetIsBot(CharacterData data, bool isBot)
		{
			try
			{
				characterDataExtensionType = characterDataExtensionType ?? AccessTools.TypeByName("RoundsWithBots.Extensions.CharacterDataExtension");
				object obj = characterDataExtensionType?.GetMethod("GetAdditionalData")?.Invoke(null, new object[1] { data });
				if (obj != null)
				{
					AccessTools.Property(obj.GetType(), "IsBot")?.SetValue(obj, isBot, null);
				}
			}
			catch (Exception ex)
			{
				RoundsReconnectPlugin.Log.LogWarning((object)$"Could not set RoundsWithBots IsBot={isBot}: {ex.Message}");
			}
		}

		public static void RefreshBotPickerList()
		{
			try
			{
				botManagerType = botManagerType ?? AccessTools.TypeByName("RoundsWithBots.BotAIManager");
				object obj = AccessTools.Field(botManagerType, "Instance")?.GetValue(null);
				AccessTools.Method(botManagerType, "SetBotsId", (Type[])null, (Type[])null)?.Invoke(obj, null);
			}
			catch (Exception ex)
			{
				RoundsReconnectPlugin.Log.LogDebug((object)("Could not refresh bot picker list: " + ex.Message));
			}
		}

		public static void ConvertToBot(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player.data == (Object)null))
			{
				CharacterData data = player.data;
				data.SetAI((Player)null);
				data.input.controlledElseWhere = true;
				PlayerAPI component = ((Component)player).GetComponent<PlayerAPI>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = true;
				}
				if ((Object)(object)((Component)player).GetComponentInChildren<PlayerAIPhilip>(true) == (Object)null)
				{
					((Component)player).gameObject.AddComponent<PlayerAIPhilip>();
				}
				SetIsBot(data, isBot: true);
			}
		}

		public static void ConvertToHuman(Player player)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player.data == (Object)null))
			{
				PlayerAIPhilip[] componentsInChildren = ((Component)player).GetComponentsInChildren<PlayerAIPhilip>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Object.Destroy((Object)(object)componentsInChildren[i]);
				}
				CharacterData data = player.data;
				data.input.controlledElseWhere = false;
				data.input.inputType = (InputType)1;
				data.playerActions = PlayerActions.CreateWithKeyboardBindings();
				((PlayerActionSet)data.playerActions).Device = null;
				PlayerAPI component = ((Component)player).GetComponent<PlayerAPI>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = false;
				}
				SetIsBot(data, isBot: false);
			}
		}
	}
	internal enum SlotState
	{
		Human,
		Abandoned,
		Bot,
		Claimed
	}
	internal sealed class SlotRecord
	{
		public string SteamId;

		public int PlayerId;

		public int TeamId;

		public int OwnerActor;

		public int ClaimActor;

		public int ViewId;

		public SlotState State;

		public bool IsClaimable
		{
			get
			{
				if (State != SlotState.Abandoned)
				{
					return State == SlotState.Bot;
				}
				return true;
			}
		}

		public string Serialize()
		{
			string[] obj = new string[7]
			{
				Escape(SteamId),
				PlayerId.ToString(),
				TeamId.ToString(),
				OwnerActor.ToString(),
				ClaimActor.ToString(),
				ViewId.ToString(),
				null
			};
			int state = (int)State;
			obj[6] = state.ToString();
			return string.Join("|", obj);
		}

		public static SlotRecord Deserialize(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return null;
			}
			string[] array = value.Split(new char[1] { '|' });
			if (array.Length != 7)
			{
				return null;
			}
			if (!int.TryParse(array[1], out var result) || !int.TryParse(array[2], out var result2) || !int.TryParse(array[3], out var result3) || !int.TryParse(array[4], out var result4) || !int.TryParse(array[5], out var result5) || !int.TryParse(array[6], out var result6))
			{
				return null;
			}
			return new SlotRecord
			{
				SteamId = Unescape(array[0]),
				PlayerId = result,
				TeamId = result2,
				OwnerActor = result3,
				ClaimActor = result4,
				ViewId = result5,
				State = (SlotState)result6
			};
		}

		public static string SerializeMany(IEnumerable<SlotRecord> slots)
		{
			return string.Join(";", (from slot in slots
				orderby slot.PlayerId
				select slot.Serialize()).ToArray());
		}

		public static List<SlotRecord> DeserializeMany(string value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return new List<SlotRecord>();
			}
			return (from slot in value.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(Deserialize)
				where slot != null
				select slot).ToList();
		}

		private static string Escape(string value)
		{
			return (value ?? string.Empty).Replace("%", "%25").Replace("|", "%7C").Replace(";", "%3B");
		}

		private static string Unescape(string value)
		{
			return (value ?? string.Empty).Replace("%3B", ";").Replace("%7C", "|").Replace("%25", "%");
		}
	}
	internal static class SteamIdentity
	{
		public static string LocalSteamId()
		{
			try
			{
				object obj = AccessTools.TypeByName("Steamworks.SteamUser")?.GetMethod("GetSteamID")?.Invoke(null, null);
				if (obj != null)
				{
					return obj.ToString();
				}
			}
			catch (Exception ex)
			{
				RoundsReconnectPlugin.Log.LogDebug((object)("Steam ID lookup failed: " + ex.Message));
			}
			Player localPlayer = PhotonNetwork.LocalPlayer;
			object obj2 = ((localPlayer != null) ? localPlayer.UserId : null);
			if (obj2 == null)
			{
				Player localPlayer2 = PhotonNetwork.LocalPlayer;
				obj2 = ((localPlayer2 != null) ? localPlayer2.NickName : null) ?? string.Empty;
			}
			return (string)obj2;
		}
	}
}
namespace RoundsReconnect.Patches
{
	[HarmonyPatch(typeof(CardChoice), "DoPick")]
	internal static class CardChoiceDoPickPatch
	{
		private static void Prefix(int picketIDToSet)
		{
			ReconnectManager.Instance?.BeforeCardPick(picketIDToSet);
		}
	}
	[HarmonyPatch(typeof(CardChoiceVisuals), "Show")]
	internal static class CardChoiceVisualsShowPatch
	{
		private static void Prefix(int pickerID)
		{
			ReconnectManager.Instance?.BeforeCardPick(pickerID);
		}
	}
	[HarmonyPatch(typeof(NetworkConnectionHandler), "CreateRoom")]
	internal static class NetworkConnectionHandlerCreateRoomPatch
	{
		private static void Prefix(RoomOptions roomOptions)
		{
			if (roomOptions != null)
			{
				roomOptions.CleanupCacheOnLeave = false;
				roomOptions.PlayerTtl = 600000;
				roomOptions.EmptyRoomTtl = 600000;
			}
		}
	}
	[HarmonyPatch(typeof(NetworkConnectionHandler), "NetworkRestart")]
	internal static class NetworkConnectionHandlerRestartPatch
	{
		private static void Prefix()
		{
			ReconnectManager.Instance?.MarkLocalSlotsAbandonedBeforeLeave();
		}
	}
	[HarmonyPatch]
	internal static class RwfGameModeStartGamePatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(AccessTools.TypeByName("RWF.GameModes.RWFGameMode"), "StartGame", (Type[])null, (Type[])null);
		}

		private static void Postfix()
		{
			ReconnectManager.Instance?.SetGameActive(active: true);
		}
	}
	[HarmonyPatch]
	internal static class RwfGameModeGameOverPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(AccessTools.TypeByName("RWF.GameModes.RWFGameMode"), "GameOver", new Type[1] { typeof(int[]) }, (Type[])null);
		}

		private static void Prefix()
		{
			ReconnectManager.Instance?.SetGameActive(active: false);
		}
	}
	[HarmonyPatch]
	internal static class RwfPrivateRoomToggleReadyPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(AccessTools.TypeByName("RWF.PrivateRoomHandler"), "ToggleReady", (Type[])null, (Type[])null);
		}

		private static bool Prefix()
		{
			int num;
			if ((Object)(object)ReconnectManager.Instance != (Object)null)
			{
				num = (ReconnectManager.Instance.ShouldBlockLobbyReady() ? 1 : 0);
				if (num != 0)
				{
					RoundsReconnectPlugin.Log.LogInfo((object)"Ready blocked: this client is waiting to reclaim an abandoned slot");
				}
			}
			else
			{
				num = 0;
			}
			return num == 0;
		}
	}
}