Decompiled source of TrueBingo v1.2.4

plugins/TrueBingo/BingoSyncSharp.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BingoSyncAPI.NetworkHandler;
using Json.Net;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BingoSyncAPI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BingoSyncAPI")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: Guid("e17f78c3-4a6b-4c43-b1ef-a454f8ae2f36")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace BingoSyncAPI
{
	public class BingoSync
	{
		public delegate void MessageReceived(BingoSyncTypes.SocketMessage socketMessage);

		public enum ConnectionStatus
		{
			Connected,
			Connecting,
			Disconnecting,
			Disconnected
		}

		private const string URL_BingoSync = "https://bingosync.com/";

		private const string URL_BignoSyncBoard = "https://bingosync.com/room/{0}/board";

		private const string URL_BignoSyncFeed = "https://bingosync.com/room/{0}/feed";

		private const string URL_BignoSyncDisconnect = "https://bingosync.com/room/{0}/disconnect";

		private const string URL_BignoSyncSettings = "https://bingosync.com/room/{0}/room-settings";

		private const string URL_API_Select = "https://bingosync.com/api/select";

		private const string URL_API_Chat = "https://bingosync.com/api/chat";

		private const string URL_API_Color = "https://bingosync.com/api/color";

		private const string URL_API_Reveal = "https://bingosync.com/api/revealed";

		private const string URL_API_NewCard = "https://bingosync.com/api/new-card";

		private const string URL_API_JoinRoom = "https://bingosync.com/api/join-room";

		private readonly Uri WSS_BingoSync = new Uri("wss://sockets.bingosync.com/broadcast");

		private WebSocketHandler socketHandler;

		public static bool DebugMode;

		private bool _boardUpdating;

		private bool _boardAwaiting;

		private string _board;

		private BingoSyncTypes.SlotInfo[] _boardSlots;

		private BingoSyncTypes.RoomSettings _roomSettings;

		private bool _waitForColor;

		public CookieContainer SessionCookies { get; private set; }

		public ConnectionStatus Status { get; private set; } = ConnectionStatus.Disconnected;


		public bool HasAnyConnection
		{
			get
			{
				if (Status != 0 && Status != ConnectionStatus.Connecting)
				{
					return Status == ConnectionStatus.Disconnecting;
				}
				return true;
			}
		}

		public BingoSyncTypes.RoomInfo CurrentRoomInfo { get; private set; }

		public event MessageReceived OnMessageReceived;

		private void MessagePassthrough(string message)
		{
			if (Status == ConnectionStatus.Disconnected)
			{
				return;
			}
			if (message == "Socket Closed")
			{
				LeaveRoom();
				return;
			}
			BingoSyncTypes.SocketMessage socketMessage = new BingoSyncTypes.SocketMessage();
			try
			{
				socketMessage = JsonNet.Deserialize<BingoSyncTypes.SocketMessage>(message);
				socketMessage.originalMsg = message;
			}
			catch
			{
				return;
			}
			if (socketMessage.type == "new-card")
			{
				_boardUpdating = true;
				UpdateBoard();
			}
			else if (socketMessage.type == "goal" && socketMessage.square?.slot != null)
			{
				UpdateBoardSlot(socketMessage.square);
			}
			this.OnMessageReceived?.Invoke(socketMessage);
		}

		public async Task<string> GetResponse(string URL, bool returnResponse, string post = null)
		{
			if (SessionCookies == null)
			{
				return string.Empty;
			}
			return await HttpWebHandler.TryGetResponse(URL, returnResponse, SessionCookies, post);
		}

		public async Task<BingoSyncTypes.CardIDs> GetCardIDs(string gameTitle, string variantTitle = "Normal", string suppliedHTML = null)
		{
			int result = 0;
			int result2 = 0;
			string text = suppliedHTML;
			if (suppliedHTML == null)
			{
				text = await GetResponse("https://bingosync.com/", returnResponse: true);
			}
			if (text == null || text == string.Empty)
			{
				return null;
			}
			try
			{
				Match match = Regex.Match(text, "value=\"(?<=)(.*?)(?=)\".?>" + Regex.Escape(gameTitle).Trim() + "</option>", RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
				if (match.Groups.Count < 2 || !int.TryParse(match.Groups[1].Value, out result))
				{
					return null;
				}
				Match match2 = Regex.Match(text, $"value=\"(?<=)(.*?)(?=)\".?data-group=\"(?<=){result}(?=)\".*?>{Regex.Escape(variantTitle).Trim()}</option>", RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
				if (match2.Groups.Count < 2 || !int.TryParse(match2.Groups[1].Value, out result2))
				{
					return null;
				}
				return new BingoSyncTypes.CardIDs(result, result2);
			}
			catch
			{
				return null;
			}
		}

		public async Task<ConnectionStatus> JoinRoom(BingoSyncTypes.RoomInfo roomInfo)
		{
			if (HasAnyConnection)
			{
				return Status;
			}
			Status = ConnectionStatus.Connecting;
			CurrentRoomInfo = null;
			SessionCookies = await HttpWebHandler.TryGetCookies(HttpWebHandler.TryGetRequest("https://bingosync.com/"));
			if (SessionCookies == null)
			{
				return Status = ConnectionStatus.Disconnected;
			}
			string text = await GetResponse("https://bingosync.com/api/join-room", returnResponse: true, BingoSyncPost.JoinRoom(roomInfo.RoomID, roomInfo.PlayerName, roomInfo.RoomPassword, roomInfo.Spectator));
			if (text == string.Empty)
			{
				return Status = ConnectionStatus.Disconnected;
			}
			socketHandler = new WebSocketHandler(WSS_BingoSync, text, MessagePassthrough);
			if (await socketHandler.StartSocket() == WebSocketHandler.ConnectionStatus.Connected)
			{
				CurrentRoomInfo = roomInfo;
				_boardUpdating = true;
				await UpdateBoardAwait();
				_waitForColor = true;
				await SetPlayerColor(CurrentRoomInfo.PlayerColor);
				Status = ConnectionStatus.Connected;
			}
			else
			{
				Status = ConnectionStatus.Disconnected;
			}
			return Status;
		}

		public async Task SetPlayerColor(BingoSyncTypes.PlayerColors playerColor)
		{
			if (Status == ConnectionStatus.Connected || _waitForColor)
			{
				if (await GetResponse("https://bingosync.com/api/color", returnResponse: true, BingoSyncPost.SetColor(CurrentRoomInfo.RoomID, playerColor.ToString().ToLower())) != string.Empty)
				{
					CurrentRoomInfo.PlayerColor = playerColor;
				}
				_waitForColor = false;
			}
		}

		public async Task SendChatMessage(string message)
		{
			if (Status == ConnectionStatus.Connected)
			{
				await GetResponse("https://bingosync.com/api/chat", returnResponse: false, BingoSyncPost.SendChat(CurrentRoomInfo.RoomID, message));
			}
		}

		public async Task RevealBoard()
		{
			if (Status == ConnectionStatus.Connected)
			{
				await GetResponse("https://bingosync.com/api/revealed", returnResponse: false, BingoSyncPost.RevealBoard(CurrentRoomInfo.RoomID));
			}
		}

		public async Task SelectSlot(int slot, bool markState = true, BingoSyncTypes.PlayerColors? color = null)
		{
			if (Status != 0)
			{
				return;
			}
			BingoSyncTypes.RoomSettings settings = await GetRoomSettings();
			if (settings != null)
			{
				BingoSyncTypes.PlayerColors colorToUse = ((!color.HasValue) ? CurrentRoomInfo.PlayerColor : color.Value);
				BingoSyncTypes.SlotInfo slotInfo = await GetBoardSlot(slot);
				bool flag = slotInfo != null && slotInfo != null && slotInfo.Colors.Contains(null);
				if ((!markState) ? (!flag && slotInfo.Colors.Contains(colorToUse)) : ((settings.lockout_mode != "Lockout" && !slotInfo.Colors.Contains(colorToUse)) || (settings.lockout_mode == "Lockout" && flag)))
				{
					await GetResponse("https://bingosync.com/api/select", returnResponse: false, BingoSyncPost.Select(CurrentRoomInfo.RoomID, slot.ToString(), colorToUse.ToString().ToLower(), !markState));
				}
			}
		}

		public async Task CreateNewCard(bool lockout_mode, bool hide_card, BingoSyncTypes.CardIDs cardIDs, int seed = -1, string custom_json = "")
		{
			if (cardIDs != null && Status == ConnectionStatus.Connected)
			{
				await GetResponse("https://bingosync.com/api/new-card", returnResponse: false, BingoSyncPost.NewCard(CurrentRoomInfo.RoomID, lockout_mode ? "2" : "1", hide_card, (seed <= -1) ? "" : Math.Abs(seed).ToString(), custom_json, cardIDs.GameID.ToString(), cardIDs.VariantID.ToString()));
			}
		}

		public async Task<BingoSyncTypes.SlotInfo[]> GetBoardSlots()
		{
			if (Status == ConnectionStatus.Connected)
			{
				while (_boardUpdating)
				{
					await Task.Yield();
				}
				return _boardSlots;
			}
			return Array.Empty<BingoSyncTypes.SlotInfo>();
		}

		public async Task<BingoSyncTypes.SlotInfo> GetBoardSlot(int slot)
		{
			if (Status == ConnectionStatus.Connected)
			{
				while (_boardUpdating)
				{
					await Task.Yield();
				}
				return _boardSlots?.FirstOrDefault((BingoSyncTypes.SlotInfo x) => x.ID == slot);
			}
			return null;
		}

		public async Task<BingoSyncTypes.RoomSettings> GetRoomSettings()
		{
			if (Status == ConnectionStatus.Connected)
			{
				while (_boardUpdating)
				{
					await Task.Yield();
				}
				return _roomSettings;
			}
			return null;
		}

		public async Task<string> GetFeed(bool full = false)
		{
			if (Status == ConnectionStatus.Connected)
			{
				return await GetFromURL(string.Format("{0}?full={1}", "https://bingosync.com/room/{0}/feed", full));
			}
			return string.Empty;
		}

		public async Task Disconnect()
		{
			if (Status == ConnectionStatus.Connected)
			{
				Status = ConnectionStatus.Disconnecting;
				await GetFromURL("https://bingosync.com/room/{0}/room-settings", response: false);
				if (socketHandler != null && socketHandler.Status == WebSocketHandler.ConnectionStatus.Connected)
				{
					await socketHandler.CloseSocket();
				}
				Status = ConnectionStatus.Disconnected;
			}
		}

		private async void UpdateBoard()
		{
			await UpdateBoardAwait();
		}

		private async Task UpdateBoardAwait()
		{
			while (_boardAwaiting)
			{
				await Task.Yield();
			}
			_boardAwaiting = true;
			_roomSettings = await UpdateRoomSettings();
			_boardSlots = await UpdateBoardSlots();
			_boardUpdating = false;
			_boardAwaiting = false;
		}

		private async Task<BingoSyncTypes.RoomSettings> UpdateRoomSettings()
		{
			string text = await GetFromURL("https://bingosync.com/room/{0}/room-settings", response: true, force: true);
			if (text == string.Empty)
			{
				return null;
			}
			string text2 = "\"settings\":";
			text = text.Substring(text.LastIndexOf(text2));
			text = text.Substring(text2.Length, text.Length - text2.Length - 1);
			try
			{
				return JsonNet.Deserialize<BingoSyncTypes.RoomSettings>(text);
			}
			catch
			{
				return null;
			}
		}

		private async Task<BingoSyncTypes.SlotInfo[]> UpdateBoardSlots()
		{
			_board = await GetFromURL("https://bingosync.com/room/{0}/board", response: true, force: true);
			if (_board == string.Empty)
			{
				return Array.Empty<BingoSyncTypes.SlotInfo>();
			}
			try
			{
				return (from x in JsonNet.Deserialize<BingoSyncTypes.Slot[]>(_board)
					select new BingoSyncTypes.SlotInfo(x)).Cast<BingoSyncTypes.SlotInfo>().ToArray();
			}
			catch
			{
				return Array.Empty<BingoSyncTypes.SlotInfo>();
			}
		}

		private async void UpdateBoardSlot(BingoSyncTypes.SocketSlot socketSlot)
		{
			string slot = socketSlot.slot;
			if (slot.Contains("slot") && int.TryParse(slot.Replace("slot", ""), out var result))
			{
				BingoSyncTypes.SlotInfo slotInfo = await GetBoardSlot(result);
				if (slotInfo != null && slotInfo.slot != null)
				{
					slotInfo.slot.name = socketSlot.name;
					slotInfo.slot.colors = socketSlot.colors;
				}
			}
		}

		private async void LeaveRoom()
		{
			await Disconnect();
		}

		private async Task<string> GetFromURL(string URL, bool response = true, bool force = false)
		{
			if (Status == ConnectionStatus.Connected || force)
			{
				return await GetResponse(string.Format(URL, CurrentRoomInfo.RoomID), response);
			}
			return string.Empty;
		}
	}
	public class BingoSyncTypes
	{
		[Serializable]
		public class CardIDs
		{
			public int GameID;

			public int VariantID;

			public CardIDs(int GameID, int VariantID)
			{
				this.GameID = GameID;
				this.VariantID = VariantID;
			}
		}

		[Serializable]
		internal class Slot
		{
			public string name;

			public string slot;

			public string colors;
		}

		[Serializable]
		public class SlotInfo
		{
			internal Slot slot;

			public string Info => slot.name;

			public int ID => int.Parse(slot.slot.Replace("slot", ""));

			public PlayerColors?[] Colors
			{
				get
				{
					if (slot.colors.Equals("blank"))
					{
						return new PlayerColors?[1];
					}
					string[] source = new string[1] { slot.colors };
					if (Enumerable.Contains(slot.colors, ' '))
					{
						source = slot.colors.Split(new char[1] { ' ' });
					}
					PlayerColors result;
					return source.Select((string x) => (!Enum.TryParse<PlayerColors>(x.Substring(0, 1).ToUpper() + x.Substring(1, x.Length - 1).ToLower(), out result)) ? null : new PlayerColors?(result)).Cast<PlayerColors?>().ToArray();
				}
			}

			internal SlotInfo(Slot slot)
			{
				this.slot = slot;
			}
		}

		[Serializable]
		public class RoomSettings
		{
			public bool hide_card { get; internal set; }

			public string lockout_mode { get; internal set; }

			public string game { get; internal set; }

			public int game_id { get; internal set; }

			public string variant { get; internal set; }

			public int variant_id { get; internal set; }

			public int seed { get; internal set; }
		}

		[Serializable]
		public class SocketMessage
		{
			public string originalMsg { get; internal set; }

			public string game { get; internal set; }

			public bool hide_card { get; internal set; }

			public bool is_current { get; internal set; }

			public string seed { get; internal set; }

			public string type { get; internal set; }

			public string event_type { get; internal set; }

			public SocketPlayer player { get; internal set; }

			public SocketSlot square { get; internal set; }

			public string player_color { get; internal set; }

			public string color { get; internal set; }

			public bool remove { get; internal set; }

			public double timestamp { get; internal set; }

			public string room { get; internal set; }

			public string text { get; internal set; }

			public string socket_key { get; internal set; }
		}

		[Serializable]
		public class SocketPlayer
		{
			public string uuid { get; internal set; }

			public string name { get; internal set; }

			public string color { get; internal set; }

			public bool is_spectator { get; internal set; }
		}

		[Serializable]
		public class SocketSlot
		{
			public string name { get; internal set; }

			public string slot { get; internal set; }

			public string colors { get; internal set; }
		}

		[Serializable]
		public class RoomInfo
		{
			public string RoomID { get; private set; }

			public string RoomPassword { get; private set; }

			public string PlayerName { get; private set; }

			public PlayerColors PlayerColor { get; internal set; }

			public bool Spectator { get; private set; }

			public RoomInfo(string RoomID, string RoomPassword, string PlayerName, PlayerColors PlayerColor, bool Spectator)
			{
				this.RoomID = RoomID;
				this.RoomPassword = RoomPassword;
				this.PlayerName = PlayerName;
				this.PlayerColor = PlayerColor;
				this.Spectator = Spectator;
			}
		}

		[Serializable]
		public enum PlayerColors
		{
			Orange,
			Red,
			Blue,
			Green,
			Purple,
			Navy,
			Teal,
			Brown,
			Pink,
			Yellow
		}
	}
	internal static class BingoSyncPost
	{
		public static string JoinRoom(string room, string nickname, string password, bool is_spectator = false)
		{
			return JsonNet.Serialize(new
			{
				room = room,
				nickname = nickname,
				password = password,
				is_specator = is_spectator
			});
		}

		public static string SetColor(string room, string color)
		{
			return JsonNet.Serialize(new { room, color });
		}

		public static string SendChat(string room, string text)
		{
			return JsonNet.Serialize(new { room, text });
		}

		public static string RevealBoard(string room)
		{
			return JsonNet.Serialize(new { room });
		}

		public static string Select(string room, string slot, string color, bool remove_color)
		{
			return JsonNet.Serialize(new { room, slot, color, remove_color });
		}

		public static string NewCard(string room, string lockout_mode, bool hide_card, string seed, string custom_json, string game_type, string variant_type)
		{
			return JsonNet.Serialize(new { hide_card, game_type, variant_type, custom_json, lockout_mode, seed, room });
		}
	}
	internal static class DebugModeOutput
	{
		public static void WriteLine(string message)
		{
			if (BingoSync.DebugMode)
			{
				Console.WriteLine(message);
			}
		}
	}
}
namespace BingoSyncAPI.NetworkHandler
{
	internal static class HttpWebHandler
	{
		private const int MaxAttempts = 3;

		public static async Task<CookieContainer> TryGetCookies(HttpWebRequest request)
		{
			string text = await GetHeader(request, HttpResponseHeader.SetCookie);
			try
			{
				if (text != string.Empty)
				{
					CookieContainer cookieContainer = new CookieContainer();
					cookieContainer.SetCookies(request.Address, text);
					return cookieContainer;
				}
				return null;
			}
			catch
			{
				return null;
			}
		}

		public static async Task<string> GetHeader(HttpWebRequest request, HttpResponseHeader header)
		{
			return await TryResponse(request, null, returnResponse: true, header);
		}

		public static async Task<string> TryGetResponse(string URL, bool returnResponse = true, CookieContainer cookies = null, string data = null)
		{
			HttpWebRequest request = TryGetRequest(URL);
			if (cookies != null)
			{
				request.CookieContainer = cookies;
			}
			DebugModeOutput.WriteLine($"Cookies: {request?.CookieContainer}");
			if (request == null)
			{
				return string.Empty;
			}
			if (data != null)
			{
				await TryPost(request, data);
			}
			DebugModeOutput.WriteLine("Post: " + data);
			return await TryResponse(request, cookies, returnResponse);
		}

		public static HttpWebRequest TryGetRequest(string URL)
		{
			if (URL == string.Empty)
			{
				return null;
			}
			try
			{
				return (HttpWebRequest)WebRequest.Create(new Uri(URL));
			}
			catch
			{
				return null;
			}
		}

		public static async Task<bool> TryPost(HttpWebRequest request, string data)
		{
			if (request == null)
			{
				return false;
			}
			int attempt = 0;
			while (attempt < 3)
			{
				attempt++;
				try
				{
					request.Method = "POST";
					request.ContentType = "application/json; charset=UTF-8";
					request.Accept = "application/json";
					using (StreamWriter stream = new StreamWriter(await request.GetRequestStreamAsync()))
					{
						await stream.WriteAsync(data);
						stream.Dispose();
					}
					return true;
				}
				catch
				{
					if (attempt >= 3)
					{
						return false;
					}
					await Task.Delay(TimeSpan.FromSeconds(1.0));
				}
			}
			return false;
		}

		public static async Task<string> TryResponse(HttpWebRequest request, CookieContainer cookies, bool returnResponse = true, HttpResponseHeader? header = null)
		{
			if (request == null)
			{
				return string.Empty;
			}
			int attempt = 0;
			string responseString = string.Empty;
			while (attempt < 3)
			{
				attempt++;
				try
				{
					using HttpWebResponse response = (HttpWebResponse)(await request.GetResponseAsync());
					if (!returnResponse)
					{
						break;
					}
					if (header.HasValue)
					{
						responseString = response.Headers[header.Value];
						response.Dispose();
					}
					else
					{
						using StreamReader reader = new StreamReader(response.GetResponseStream());
						responseString = await reader.ReadToEndAsync();
						response.Dispose();
						reader.Dispose();
					}
					response.Close();
				}
				catch
				{
					DebugModeOutput.WriteLine($"Failed Response Attempt: {attempt}");
					DebugModeOutput.WriteLine("(" + request?.Address?.ToString() + ") Did not like request...");
					if (attempt >= 3)
					{
						return string.Empty;
					}
					if (cookies != null)
					{
						request = TryGetRequest(request.RequestUri.AbsoluteUri);
						if (request != null)
						{
							request.CookieContainer = cookies;
						}
					}
					await Task.Delay(TimeSpan.FromSeconds(1.0));
					continue;
				}
				break;
			}
			return responseString ?? string.Empty;
		}
	}
	internal class WebSocketHandler
	{
		public delegate void MessageReceived(string message);

		public enum ConnectionStatus
		{
			Connected,
			Connecting,
			Disconnected,
			Disconnecting
		}

		private MessageReceived messageReceiver;

		private const int MaxAttempts = 3;

		private ClientWebSocket socket;

		public Uri URI { get; private set; }

		public string SocketKey { get; private set; }

		public ConnectionStatus Status { get; private set; } = ConnectionStatus.Disconnected;


		public event MessageReceived OnMessageReceived;

		public WebSocketHandler(Uri URI, string socketKey, MessageReceived messageReceiver)
		{
			this.URI = URI;
			SocketKey = socketKey;
			this.messageReceiver = messageReceiver;
			OnMessageReceived += messageReceiver;
		}

		public async Task<ConnectionStatus> StartSocket()
		{
			if (Status != 0 && Status != ConnectionStatus.Connecting && Status != ConnectionStatus.Disconnecting)
			{
				Status = ConnectionStatus.Connecting;
				OpenSocket();
				return await WaitForConnection();
			}
			return Status;
		}

		private async Task<ConnectionStatus> WaitForConnection()
		{
			while (Status == ConnectionStatus.Connecting)
			{
				await Task.Yield();
			}
			return Status;
		}

		private async void OpenSocket()
		{
			byte[] socketData = Encoding.ASCII.GetBytes(SocketKey);
			using (ClientWebSocket socket = new ClientWebSocket())
			{
				await socket.ConnectAsync(URI, CancellationToken.None);
				if (socket.State == WebSocketState.Open)
				{
					try
					{
						await socket.SendAsync(new ArraySegment<byte>(socketData), WebSocketMessageType.Text, endOfMessage: true, CancellationToken.None);
					}
					catch
					{
						Status = ConnectionStatus.Disconnected;
					}
					if (Status == ConnectionStatus.Connecting)
					{
						this.socket = socket;
						await StartListeningToSocket();
					}
				}
			}
			OnMessageReceived -= messageReceiver;
			Status = ConnectionStatus.Disconnected;
		}

		private async Task StartListeningToSocket()
		{
			Status = ConnectionStatus.Connected;
			await ReceiveMessages();
		}

		private async Task ReceiveMessages()
		{
			byte[] buffer = new byte[1024];
			int attempt = 0;
			while (socket.State == WebSocketState.Open && Status == ConnectionStatus.Connected && attempt < 3)
			{
				attempt++;
				WebSocketReceiveResult result;
				try
				{
					result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
					attempt = 0;
				}
				catch
				{
					if (attempt >= 3)
					{
						await CloseSocket();
						break;
					}
					await Task.Delay(TimeSpan.FromSeconds(1.0));
					continue;
				}
				if (result.MessageType == WebSocketMessageType.Close && Status == ConnectionStatus.Connected)
				{
					await CloseSocket();
					break;
				}
				if (result != null)
				{
					string @string = Encoding.UTF8.GetString(buffer, 0, result.Count);
					if (@string != null && @string != string.Empty)
					{
						this.OnMessageReceived?.Invoke(@string);
					}
				}
			}
		}

		public async Task CloseSocket()
		{
			if (socket != null && socket.State == WebSocketState.Open && Status == ConnectionStatus.Connected)
			{
				Status = ConnectionStatus.Disconnecting;
				WebSocketCloseStatus closeStatus = socket.CloseStatus.GetValueOrDefault(WebSocketCloseStatus.NormalClosure);
				string closeReason = socket.CloseStatusDescription;
				try
				{
					await socket.CloseOutputAsync(closeStatus, closeReason, CancellationToken.None);
					await socket.CloseAsync(closeStatus, closeReason, CancellationToken.None);
				}
				catch
				{
				}
				Status = ConnectionStatus.Disconnected;
				socket = null;
				this.OnMessageReceived?.Invoke("Socket Closed");
			}
		}
	}
}
namespace Json.Net
{
	[ComVisible(true)]
	public interface IJsonConverter
	{
		Type GetConvertingType();

		string Serializer(object obj);

		object Deserializer(string txt);
	}
	[ComVisible(true)]
	public interface IPropertyNameTransform
	{
		string Transform(string propertyName);
	}
	[ComVisible(true)]
	public class JsonConverter<T> : IJsonConverter
	{
		public Func<T, string> Serializer;

		public Func<string, T> Deserializer;

		public JsonConverter(Func<T, string> serializer, Func<string, T> deserializer)
		{
			Serializer = serializer;
			Deserializer = deserializer;
		}

		Type IJsonConverter.GetConvertingType()
		{
			return typeof(T);
		}

		string IJsonConverter.Serializer(object obj)
		{
			return Serializer((T)obj);
		}

		object IJsonConverter.Deserializer(string txt)
		{
			return Deserializer(txt);
		}
	}
	[ComVisible(true)]
	public static class JsonNet
	{
		public static T Deserialize<T>(string json, SerializationOptions options = null)
		{
			return (T)JsonParser.Instance.Initialize(json, options).FromJson(typeof(T));
		}

		public static T Deserialize<T>(Stream stream, SerializationOptions options = null)
		{
			return (T)JsonParser.Instance.Initialize(new StreamReader(stream), options).FromJson(typeof(T));
		}

		public static T Deserialize<T>(TextReader reader, SerializationOptions options = null)
		{
			return (T)JsonParser.Instance.Initialize(reader, options).FromJson(typeof(T));
		}

		public static string Serialize(object obj, SerializationOptions options = null)
		{
			JsonSerializer jsonSerializer = JsonSerializer.Instance.Initialize();
			jsonSerializer.Serialize(obj, options);
			return jsonSerializer.Builder.ToString();
		}

		public static void Serialize(object obj, Stream stream, SerializationOptions options = null)
		{
			using StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, leaveOpen: true);
			Serialize(obj, writer, options);
		}

		public static void Serialize(object obj, TextWriter writer, SerializationOptions options = null)
		{
			JsonSerializer.Instance.Initialize(writer).Serialize(obj, options);
			writer.Flush();
		}

		public static T Deserialize<T>(string json, params IJsonConverter[] converters)
		{
			return Deserialize<T>(json, new SerializationOptions
			{
				Converters = converters
			});
		}

		public static T Deserialize<T>(Stream stream, params IJsonConverter[] converters)
		{
			return Deserialize<T>(new StreamReader(stream), new SerializationOptions
			{
				Converters = converters
			});
		}

		public static T Deserialize<T>(TextReader reader, params IJsonConverter[] converters)
		{
			return Deserialize<T>(reader, new SerializationOptions
			{
				Converters = converters
			});
		}

		public static string Serialize(object obj, params IJsonConverter[] converters)
		{
			return Serialize(obj, new SerializationOptions
			{
				Converters = converters
			});
		}

		public static void Serialize(object obj, Stream stream, params IJsonConverter[] converters)
		{
			Serialize(obj, stream, new SerializationOptions
			{
				Converters = converters
			});
		}

		public static void Serialize(object obj, TextWriter writer, params IJsonConverter[] converters)
		{
			Serialize(obj, new SerializationOptions
			{
				Converters = converters
			});
		}

		public static T Deserialize<T>(string json, IPropertyNameTransform propertyNameTransform, params IJsonConverter[] converters)
		{
			return Deserialize<T>(json, new SerializationOptions
			{
				PropertyNameTransform = propertyNameTransform,
				Converters = converters
			});
		}

		public static T Deserialize<T>(Stream stream, IPropertyNameTransform propertyNameTransform, params IJsonConverter[] converters)
		{
			return Deserialize<T>(new StreamReader(stream), new SerializationOptions
			{
				PropertyNameTransform = propertyNameTransform,
				Converters = converters
			});
		}

		public static T Deserialize<T>(TextReader reader, IPropertyNameTransform propertyNameTransform, params IJsonConverter[] converters)
		{
			return Deserialize<T>(reader, new SerializationOptions
			{
				PropertyNameTransform = propertyNameTransform,
				Converters = converters
			});
		}

		public static string Serialize(object obj, IPropertyNameTransform propertyNameTransform, params IJsonConverter[] converters)
		{
			return Serialize(obj, new SerializationOptions
			{
				PropertyNameTransform = propertyNameTransform,
				Converters = converters
			});
		}

		public static void Serialize(object obj, Stream stream, IPropertyNameTransform propertyNameTransform, params IJsonConverter[] converters)
		{
			Serialize(obj, stream, new SerializationOptions
			{
				PropertyNameTransform = propertyNameTransform,
				Converters = converters
			});
		}

		public static void Serialize(object obj, TextWriter writer, IPropertyNameTransform propertyNameTransform, params IJsonConverter[] converters)
		{
			Serialize(obj, new SerializationOptions
			{
				PropertyNameTransform = propertyNameTransform,
				Converters = converters
			});
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = true)]
	[ComVisible(true)]
	public sealed class JsonNetIgnoreAttribute : Attribute
	{
	}
	[ComVisible(true)]
	public class JsonParser : ParserBase
	{
		private IJsonConverter[] Converters;

		private IPropertyNameTransform PropertyNameTransform;

		private static Dictionary<char, char> EscapeMap = new Dictionary<char, char>
		{
			{ 'b', '\b' },
			{ 't', '\t' },
			{ 'n', '\n' },
			{ 'f', '\f' },
			{ 'r', '\r' }
		};

		[ThreadStatic]
		private static JsonParser _Instance;

		private StringBuilder text = new StringBuilder();

		public static JsonParser Instance => _Instance ?? (_Instance = new JsonParser());

		public JsonParser Initialize(string json, SerializationOptions options)
		{
			Initialize(json);
			Converters = options?.Converters;
			PropertyNameTransform = options?.PropertyNameTransform;
			return this;
		}

		public JsonParser Initialize(TextReader jsonReader, SerializationOptions options)
		{
			Initialize(jsonReader);
			Converters = options?.Converters;
			PropertyNameTransform = options.PropertyNameTransform;
			return this;
		}

		public object FromJson(Type type)
		{
			SkipWhite();
			if (NextChar == '{')
			{
				if (type == null || type == typeof(object) || type == typeof(ExpandoObject))
				{
					type = typeof(ExpandoObject);
				}
				ReadNext();
				SkipWhite();
				if (type.IsValueType)
				{
					throw new FormatException("Unexpected type!");
				}
				object obj = Activator.CreateInstance(type);
				Type type2 = ((obj is IDictionary) ? type.GenericTypeArguments[0] : typeof(string));
				Type type3 = ((obj is IDictionary) ? type.GenericTypeArguments[1] : null);
				int num = 0;
				while (NextChar != '}')
				{
					object obj2 = FromJson(type2);
					SkipWhite();
					Match(":");
					SerializerMap serializerMap = SerializerMap.GetSerializerMap(type);
					MemberAccessor memberAccessor = null;
					if (type3 == null)
					{
						if (serializerMap.Members.Length == 0)
						{
							memberAccessor = GetFieldAccessorFor(obj2.ToString());
						}
						else
						{
							for (int i = num; i < serializerMap.Members.Length; i++)
							{
								string text = serializerMap.Members[i].Name;
								if (PropertyNameTransform != null)
								{
									text = PropertyNameTransform.Transform(text);
								}
								string text2 = obj2.ToString();
								if (text == text2 || text.Equals(text2, StringComparison.InvariantCultureIgnoreCase))
								{
									memberAccessor = serializerMap.Members[i];
									break;
								}
							}
						}
					}
					Type type4 = ((memberAccessor == null) ? type3 : memberAccessor.ValueType);
					if (type4 == null)
					{
						FromJson(type4);
					}
					else
					{
						object obj3 = FromJson(type4);
						if (memberAccessor != null)
						{
							try
							{
								memberAccessor.SetValue(obj, obj3);
							}
							catch
							{
							}
						}
						else
						{
							((IDictionary)obj).Add(obj2, obj3);
						}
					}
					SkipWhite();
					if (NextChar != ',')
					{
						break;
					}
					ReadNext();
					SkipWhite();
				}
				Match("}");
				return obj;
			}
			if (NextChar == '[')
			{
				if (type == null || type == typeof(object) || type == typeof(ExpandoObject))
				{
					type = typeof(object[]);
				}
				ReadNext();
				SkipWhite();
				Type type5 = (type.IsArray ? type.GetElementType() : (type.IsGenericType ? type.GenericTypeArguments[0] : typeof(object)));
				IList list = (type.IsArray ? new ArrayList() : ((!(type == typeof(IEnumerable))) ? ((IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type5))) : new List<object>()));
				while (NextChar != ']')
				{
					object value = FromJson(type5);
					list.Add(value);
					SkipWhite();
					if (NextChar != ',')
					{
						break;
					}
					ReadNext();
					SkipWhite();
				}
				Match("]");
				if (list is ArrayList)
				{
					return ((ArrayList)list).ToArray(type5);
				}
				return list;
			}
			if (NextChar == '"')
			{
				if (type == null || type == typeof(object) || type == typeof(ExpandoObject))
				{
					type = typeof(string);
				}
				ReadNext();
				while (!EndOfStream && NextChar != '"')
				{
					if (NextChar == '\\')
					{
						ReadNext();
						switch (NextChar)
						{
						case 'b':
						case 'f':
						case 'n':
						case 'r':
						case 't':
							this.text.Append(EscapeMap[NextChar]);
							break;
						case 'u':
						{
							ReadNext();
							string text3 = "";
							while (text3.Length < 4 && base.IsHexDigit)
							{
								text3 += NextChar;
								ReadNext();
							}
							this.text.Append(char.ConvertFromUtf32(int.Parse("0x" + text3)));
							continue;
						}
						default:
							this.text.Append(NextChar);
							break;
						}
					}
					else
					{
						this.text.Append(NextChar);
					}
					ReadNext();
				}
				SkipWhite();
				Match("\"");
				object obj = this.text.ToString();
				this.text.Clear();
				IJsonConverter jsonConverter = Converters?.FirstOrDefault((IJsonConverter c) => c.GetConvertingType() == type);
				if (jsonConverter != null)
				{
					return jsonConverter.Deserializer((string)obj);
				}
				if (type == typeof(DateTime) || type == typeof(DateTime?))
				{
					return DateTime.Parse((string)obj, CultureInfo.InvariantCulture);
				}
				if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?))
				{
					return DateTimeOffset.Parse((string)obj, CultureInfo.InvariantCulture);
				}
				if (type == typeof(TimeSpan) || type == typeof(TimeSpan?))
				{
					return TimeSpan.Parse((string)obj, CultureInfo.InvariantCulture);
				}
				if (type == typeof(Guid) || type == typeof(Guid?))
				{
					return Guid.Parse((string)obj);
				}
				try
				{
					return Convert.ChangeType(obj, type);
				}
				catch
				{
					throw new FormatException($"'{obj}' cannot be converted to {type.Name}");
				}
			}
			if (NextChar == 't')
			{
				Match("true");
				return true;
			}
			if (NextChar == 'f')
			{
				Match("false");
				return false;
			}
			if (NextChar == 'n')
			{
				Match("null");
				if (type == null)
				{
					type = typeof(object);
				}
				if (!type.IsClass && !type.IsInterface && !(Nullable.GetUnderlyingType(type) != null))
				{
					throw new InvalidDataException("Type " + type.Name + "'s value cannot be null!");
				}
				return null;
			}
			if (NextChar == '-' || base.IsDigit)
			{
				if (type == null || type == typeof(object))
				{
					type = typeof(double);
				}
				if (NextChar == '-')
				{
					this.text.Append('-');
					ReadNext();
				}
				if (NextChar == '0')
				{
					this.text.Append('0');
					ReadNext();
				}
				else
				{
					if (!base.IsDigit)
					{
						throw new FormatException("Digit expected!");
					}
					do
					{
						this.text.Append(NextChar);
						ReadNext();
					}
					while (base.IsDigit);
				}
				if (NextChar == '.')
				{
					this.text.Append('.');
					ReadNext();
					while (base.IsDigit)
					{
						this.text.Append(NextChar);
						ReadNext();
					}
				}
				if (NextChar == 'e' || NextChar == 'E')
				{
					this.text.Append('e');
					ReadNext();
					if (NextChar == '+' || NextChar == '-')
					{
						this.text.Append(NextChar);
						ReadNext();
					}
					while (base.IsDigit)
					{
						this.text.Append(NextChar);
						ReadNext();
					}
				}
				string text4 = this.text.ToString();
				this.text.Clear();
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				if (type.IsGenericType && type.IsValueType && Nullable.GetUnderlyingType(type).IsEnum)
				{
					type = Nullable.GetUnderlyingType(type);
				}
				if (type.IsEnum)
				{
					return Enum.Parse(type, text4);
				}
				if (type == typeof(int) || type == typeof(int?))
				{
					return int.Parse(text4, invariantCulture);
				}
				if (type == typeof(long) || type == typeof(long?))
				{
					return long.Parse(text4, invariantCulture);
				}
				return double.Parse(text4, invariantCulture);
			}
			throw new FormatException("Unexpected character! " + NextChar);
		}

		private MemberAccessor GetFieldAccessorFor(string fieldName)
		{
			string tName = fieldName.ToString();
			if (PropertyNameTransform != null)
			{
				tName = PropertyNameTransform.Transform(tName);
			}
			return new MemberAccessor
			{
				Name = tName,
				ValueType = typeof(ExpandoObject),
				GetValue = (object o) => ((IDictionary<string, object>)(ExpandoObject)o)[tName],
				SetValue = delegate(object o, object v)
				{
					((IDictionary<string, object>)(ExpandoObject)o)[tName] = v;
				}
			};
		}
	}
	[ComVisible(true)]
	public class JsonSerializer
	{
		private TextWriter Writer;

		public StringBuilder Builder = new StringBuilder(1024);

		protected Action<string> Write;

		[ThreadStatic]
		private static JsonSerializer _Instance;

		private static Dictionary<Type, Func<object, string>> SerializerCache = new Dictionary<Type, Func<object, string>>();

		public static JsonSerializer Instance => _Instance ?? (_Instance = new JsonSerializer());

		public JsonSerializer Initialize()
		{
			Writer = null;
			Builder.Clear();
			Write = delegate(string s)
			{
				Builder.Append(s);
			};
			return this;
		}

		public JsonSerializer Initialize(TextWriter writer)
		{
			Writer = writer;
			Write = delegate(string s)
			{
				Writer.Write(s);
			};
			return this;
		}

		public void Serialize(object obj, SerializationOptions options)
		{
			if (obj == null)
			{
				Write("null");
				return;
			}
			Type objectType = obj.GetType();
			IJsonConverter jsonConverter = options?.Converters?.FirstOrDefault((IJsonConverter c) => c.GetConvertingType() == objectType);
			if (jsonConverter != null)
			{
				Serialize(jsonConverter.Serializer(obj), options);
				return;
			}
			if (!SerializerCache.TryGetValue(objectType, out var value))
			{
				Func<object, string> strConverter = delegate(object s)
				{
					string text = (string)s;
					string text2 = "\"";
					for (int j = 0; j < text.Length; j++)
					{
						char c2 = text[j];
						text2 += c2 switch
						{
							'\f' => "\\f", 
							'\b' => "\\b", 
							'/' => "\\/", 
							'\\' => "\\\\", 
							'"' => "\\\"", 
							'\t' => "\\t", 
							'\n' => "\\n", 
							'\r' => "\\r", 
							_ => c2.ToString(), 
						};
					}
					return text2 + "\"";
				};
				if (obj is string)
				{
					value = strConverter;
				}
				else
				{
					if (obj is IEnumerable && !(obj is ExpandoObject))
					{
						Write((obj is IDictionary) ? "{" : "[");
						bool flag = true;
						foreach (object item in (IEnumerable)obj)
						{
							if (flag)
							{
								flag = false;
							}
							else
							{
								Write(",");
							}
							Serialize(item, options);
						}
						Write((obj is IDictionary) ? "}" : "]");
						return;
					}
					if (obj is bool || obj is bool?)
					{
						value = (object b) => (!(bool)b) ? "false" : "true";
					}
					else if (obj is Guid || obj is Guid?)
					{
						value = (object g) => strConverter(((Guid)g).ToString());
					}
					else if (obj is int || obj is int? || obj is short || obj is short? || obj is long || obj is long? || obj is uint || obj is uint? || obj is ushort || obj is ushort? || obj is ulong || obj is ulong? || obj is float || obj is float? || obj is double || obj is double? || obj is decimal || obj is decimal? || obj is float || obj is uint? || obj is ushort || obj is ushort? || obj is ulong || obj is ulong?)
					{
						value = (object n) => string.Format(CultureInfo.InvariantCulture, "{0}", n);
					}
					else if (obj is DateTime || obj is DateTime?)
					{
						value = (object d) => strConverter(((DateTime)d).ToString(CultureInfo.InvariantCulture));
					}
					else if (obj is DateTimeOffset || obj is DateTimeOffset?)
					{
						value = (object d) => strConverter(((DateTimeOffset)d).ToString(CultureInfo.InvariantCulture));
					}
					else if (obj is TimeSpan || obj is TimeSpan?)
					{
						value = (object d) => strConverter(((TimeSpan)d).ToString("c"));
					}
					else if (obj is Enum)
					{
						value = (object e) => ((int)e).ToString(CultureInfo.InvariantCulture);
					}
					else
					{
						Type type;
						if (objectType.IsGenericType && objectType.GenericTypeArguments.Length == 2 && objectType == (type = typeof(KeyValuePair<, >).MakeGenericType(objectType.GenericTypeArguments)))
						{
							string arg = type.GetProperty("Key").GetValue(obj).ToString();
							object value2 = type.GetProperty("Value").GetValue(obj);
							Write(strConverter(arg));
							Write(":");
							Serialize(value2, options);
							return;
						}
						if (!objectType.IsPrimitive)
						{
							Write("{");
							bool flag2 = true;
							MemberAccessor[] array = SerializerMap.GetSerializerMap(objectType).Members;
							if (array.Length == 0)
							{
								array = ((IDictionary<string, object>)(ExpandoObject)obj).Keys.Select((string m) => GetFieldAccessorFor(m)).ToArray();
							}
							MemberAccessor[] array2 = array;
							foreach (MemberAccessor memberAccessor in array2)
							{
								if (flag2)
								{
									flag2 = false;
								}
								else
								{
									Write(",");
								}
								if (objectType == typeof(DictionaryEntry))
								{
									DictionaryEntry dictionaryEntry = (DictionaryEntry)obj;
									Write(strConverter(dictionaryEntry.Key.ToString()));
									Write(":");
									Serialize(dictionaryEntry.Value, options);
									continue;
								}
								string arg2 = memberAccessor.Name;
								if (options?.PropertyNameTransform != null)
								{
									arg2 = options?.PropertyNameTransform.Transform(memberAccessor.Name);
								}
								Write(strConverter(arg2));
								Write(":");
								try
								{
									Serialize(memberAccessor.GetValue(obj), options);
								}
								catch (TargetInvocationException)
								{
									Serialize(null, options);
								}
							}
							Write("}");
							return;
						}
					}
				}
				SerializerCache[objectType] = value ?? throw new InvalidOperationException("Unknown object type! " + objectType.FullName);
			}
			Write(value(obj));
		}

		private MemberAccessor GetFieldAccessorFor(string fieldName)
		{
			return new MemberAccessor
			{
				Name = fieldName,
				ValueType = typeof(ExpandoObject),
				GetValue = (object o) => ((IDictionary<string, object>)(ExpandoObject)o)[fieldName],
				SetValue = delegate(object o, object v)
				{
					((IDictionary<string, object>)(ExpandoObject)o)[fieldName] = v;
				}
			};
		}
	}
	[ComVisible(true)]
	public class ParserBase
	{
		private TextReader Reader;

		private char[] ReaderBuffer;

		private string Buffer;

		private int BufferIndex;

		protected char NextChar;

		private const char EOF = '\u001b';

		protected bool EndOfStream;

		protected static string WhiteSpace = " \t\r\n";

		protected static string Digits = "0123456789";

		protected static string HexDigits = "0123456789ABCDEFabcdef";

		protected static string Alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

		protected static string AlphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

		private IEnumerator<char> _Stream;

		protected bool IsWhite => WhiteSpace.IndexOf(NextChar) >= 0;

		protected bool IsAlpha => Alpha.IndexOf(NextChar) >= 0;

		protected bool IsAlphaNumeric => AlphaNumeric.IndexOf(NextChar) >= 0;

		protected bool IsDigit => Digits.IndexOf(NextChar) >= 0;

		protected bool IsHexDigit => HexDigits.IndexOf(NextChar) >= 0;

		public ParserBase(int bufferSize = 1024)
		{
			ReaderBuffer = new char[bufferSize];
		}

		private ParserBase _Initialize()
		{
			EndOfStream = false;
			BufferIndex = -1;
			_Stream = _ReadNext().GetEnumerator();
			ReadNext();
			return this;
		}

		public ParserBase Initialize(string json)
		{
			Reader = null;
			Buffer = json;
			return _Initialize();
		}

		public ParserBase Initialize(TextReader textReader)
		{
			Reader = textReader;
			Buffer = "";
			return _Initialize();
		}

		protected char ReadNext()
		{
			_Stream.MoveNext();
			return NextChar = _Stream.Current;
		}

		private IEnumerable<char> _ReadNext()
		{
			if (EndOfStream)
			{
				yield break;
			}
			if (Reader == null)
			{
				while (++BufferIndex < Buffer.Length)
				{
					yield return Buffer[BufferIndex];
				}
				Buffer = "";
				BufferIndex = 0;
				EndOfStream = true;
				yield return '\u001b';
				yield break;
			}
			while (true)
			{
				int read = Reader.ReadBlock(ReaderBuffer, 0, ReaderBuffer.Length);
				Buffer = new string(ReaderBuffer, 0, read);
				BufferIndex = -1;
				while (read-- > 0)
				{
					yield return Buffer[++BufferIndex];
				}
			}
		}

		protected void SkipWhite()
		{
			while (IsWhite)
			{
				ReadNext();
			}
		}

		protected void Match(string s)
		{
			foreach (char c in s)
			{
				if (NextChar == c)
				{
					ReadNext();
					continue;
				}
				throw new FormatException(s + " expected, but " + NextChar + " found!");
			}
		}
	}
	[ComVisible(true)]
	public enum Gender
	{
		None,
		Female,
		Male,
		Other
	}
	[DataContract]
	[ComVisible(true)]
	public class Pet
	{
		public static string OriginalPetJson = "{\"id\":1,\"name\":\"gucci\",\"birth\":\"08/30/2012 13:41:59\",\"alive\":true,\"gender\":1,\"dictType\":{\"Key1\":\"Value1\",\"Key2\":\"Value2\"},\"intArray\":[1,2,3]}";

		public static Pet OriginalPet = new Pet
		{
			id = 1,
			name = "gucci",
			birth = new DateTime(2012, 8, 30, 13, 41, 59),
			alive = true,
			gender = Gender.Male,
			dictType = new Dictionary<string, string>
			{
				{ "Key1", "Value1" },
				{ "Key2", "Value2" }
			},
			intArray = new int[3] { 1, 2, 3 }
		};

		[DataMember]
		public int id { get; set; }

		[DataMember]
		public string name { get; set; }

		[DataMember]
		public DateTime birth { get; set; }

		[DataMember]
		public bool alive { get; set; }

		[DataMember]
		public Gender gender { get; set; }

		[DataMember]
		public Dictionary<string, string> dictType { get; set; }

		[DataMember]
		public int[] intArray { get; set; }
	}
	[ComVisible(true)]
	public static class PropertyNameTransforms
	{
		public static IPropertyNameTransform TitleToCamelCase { get; } = new TitleToCamelCase();

	}
	[ComVisible(true)]
	public class SerializationOptions
	{
		public IJsonConverter[] Converters { get; set; }

		public IPropertyNameTransform PropertyNameTransform { get; set; }
	}
	[ComVisible(true)]
	public class MemberAccessor
	{
		public string Name;

		public Type ValueType;

		public Func<object, object> GetValue;

		public Action<object, object> SetValue;
	}
	[ComVisible(true)]
	public class SerializerMap
	{
		public readonly Type ObjectType;

		public readonly MemberAccessor[] Members;

		[ThreadStatic]
		private static SerializerMap[] _GlobalMaps;

		private string[] IgnoredAttributes = new string[4] { "JsonIgnoreAttribute", "JsonNetIgnoreAttribute", "NonSerializedAttribute", "XmlIgnoreAttribute" };

		private static SerializerMap[] GlobalMaps => _GlobalMaps ?? (_GlobalMaps = new SerializerMap[0]);

		public SerializerMap(Type type)
		{
			SerializerMap serializerMap = this;
			ObjectType = type;
			if (type == typeof(object) || type == typeof(ExpandoObject))
			{
				Members = new MemberAccessor[0];
				return;
			}
			Members = (from m in type.GetMembers(BindingFlags.Instance | BindingFlags.Public)
				where m.MemberType == MemberTypes.Field || (m.MemberType == MemberTypes.Property && type.GetProperty(m.Name).CanRead && !(from a in m.GetCustomAttributes()
					select a.GetType().Name).Intersect(serializerMap.IgnoredAttributes).Any())
				select (m.MemberType != MemberTypes.Property) ? new MemberAccessor
				{
					Name = m.Name,
					ValueType = ((FieldInfo)m).FieldType,
					GetValue = ((FieldInfo)m).GetValue,
					SetValue = ((FieldInfo)m).SetValue
				} : new MemberAccessor
				{
					Name = m.Name,
					ValueType = ((PropertyInfo)m).PropertyType,
					GetValue = ((PropertyInfo)m).GetValue,
					SetValue = ((PropertyInfo)m).SetValue
				}).ToArray();
		}

		public static SerializerMap GetSerializerMap(Type type)
		{
			SerializerMap serializerMap;
			if ((serializerMap = GlobalMaps.FirstOrDefault((SerializerMap m) => m.ObjectType == type)) == null)
			{
				lock (_GlobalMaps)
				{
					if ((serializerMap = _GlobalMaps.FirstOrDefault((SerializerMap m) => m.ObjectType == type)) == null)
					{
						int num = _GlobalMaps.Length;
						Array.Resize(ref _GlobalMaps, num + 1);
						serializerMap = (_GlobalMaps[num] = new SerializerMap(type));
						foreach (Type item in (from v in serializerMap.Members
							select v.ValueType into t
							where t != typeof(string) && (t.IsClass || (t.IsValueType && !t.IsPrimitive))
							select t).Except(GlobalMaps.Select((SerializerMap m) => m.ObjectType)).Distinct())
						{
							GetSerializerMap(item);
						}
					}
				}
			}
			return serializerMap;
		}
	}
	[ComVisible(true)]
	public class TitleToCamelCase : IPropertyNameTransform
	{
		public string Transform(string propertyName)
		{
			return char.ToLowerInvariant(propertyName[0]) + propertyName.Substring(1);
		}
	}
}

plugins/TrueBingo/TrueBingo.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BingoSyncAPI;
using HarmonyLib;
using Reptile;
using Reptile.Phone;
using TMPro;
using TrueBingo.BingoSyncManager;
using TrueBingo.Components;
using TrueBingo.Patches;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Playables;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("TrueBingo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TrueBingo")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ca007dd4-4557-4d77-af3f-81f55fd407a3")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace TrueBingo
{
	public static class BingoConfig
	{
		private struct ConfigEntry
		{
			public ConfigFile configFile;

			public string selection;

			public ConfigEntry(ConfigFile configFile, string selection)
			{
				this.configFile = configFile;
				this.selection = selection;
			}
		}

		private static ConfigFile config_char;

		private static ConfigFile config_world;

		public static ConfigFile config_bingosync;

		private static string config_char_path_full;

		private static string config_world_path_full;

		private static string config_bingosync_path_full;

		private const string config_foldername = "TrueBingo";

		private const string config_char_filename = "Character";

		private const string config_world_filename = "World";

		private const string config_bingosync_filename = "BingoSync";

		private const string config_filetype = "cfg";

		private const string config_selection_char = "Character Settings";

		private const string config_selection_world = "World Settings";

		public const string config_selection_bingosync = "BingoSync";

		private static ConfigEntry characterEntry;

		private const string characterEntry_char = "Character";

		private const string characterEntry_style = "Style";

		private const string characterEntry_outfit = "Outfit";

		private static ConfigEntry worldEntry;

		private const string worldEntry_stage = "Starting Stage";

		private const string worldEntry_pos = "Starting Position";

		private const string worldEntry_seed = "Seed";

		private const string worldEntry_story = "Disable Story";

		private const string worldEntry_bmx = "Disable BMX Doors";

		private const string worldEntry_taxi = "Enable Taxi Fight";

		private const string worldEntry_boss = "Enable Final Boss Trigger";

		private const string worldEntry_cops = "Disable Cops";

		private const string worldEntry_roboskip = "Open Teleport Robo-Posts";

		private const string worldEntry_cutscene = "Allow Skipping All Cutscenes";

		private const string worldEntry_fastcutscene = "Fast Cutscene Skip";

		private const string worldEntry_repdisplay = "Always Display REP";

		private const string worldEntry_mallvinyl = "Skip Mall Vinyl";

		private static ConfigEntry bingoSyncEntry;

		public const string bingoSyncEntry_roomID = "Room ID";

		public const string bingoSyncEntry_password = "Room Password";

		public const string bingoSyncEntry_name = "Player Name";

		public const string bingoSyncEntry_color = "Player Color";

		public const string bingoSyncEntry_autoconnect = "Auto-Connect";

		public const string bingoSyncEntry_phonenoti = "Notifications";

		public const string bingoSyncEntry_key = "Menu Key";

		public static Characters character;

		public static MoveStyle moveStyle;

		public static int outfit;

		public static Stage stage;

		public static int seed;

		public static Vector3 position;

		public static bool disableStory;

		public static bool disableBMX;

		public static bool enableTaxi;

		public static bool enableBoss;

		public static bool disableCops;

		public static bool roboSkip;

		public static bool cutsceneSkip;

		public static bool fastCutscene;

		public static bool repDisplay;

		public static bool skipMallVinyl;

		public static bool autoconnect;

		public static bool phonenotification;

		public static KeyCode menukey;

		public static void InitConfigs()
		{
			CreateConfig();
			FillConfigs();
			ReloadConfigs();
		}

		private static void CreateConfig()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			config_char_path_full = GetFilePath("TrueBingo", "Character", "cfg");
			config_char = new ConfigFile(config_char_path_full, true);
			config_world_path_full = GetFilePath("TrueBingo", "World", "cfg");
			config_world = new ConfigFile(config_world_path_full, true);
			config_bingosync_path_full = GetFilePath("TrueBingo", "BingoSync", "cfg");
			config_bingosync = new ConfigFile(config_bingosync_path_full, true);
		}

		private static string GetFilePath(string foldername, string filename, string filetype)
		{
			return Path.Combine(Paths.ConfigPath, foldername + "\\" + filename + "." + filetype);
		}

		private static void FillConfigs()
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			characterEntry = new ConfigEntry(config_char, "Character Settings");
			BindConfig(characterEntry, "Character", BingoConfigTypes.Characters.Red);
			BindConfig(characterEntry, "Style", BingoConfigTypes.Styles.Skateboard);
			BindConfig(characterEntry, "Outfit", BingoConfigTypes.Outfits.Spring);
			worldEntry = new ConfigEntry(config_world, "World Settings");
			BindConfig(worldEntry, "Starting Stage", BingoConfigTypes.Stages.Hideout);
			BindConfig<Vector3>(worldEntry, "Starting Position", new Vector3(-5f, 3f, 43f), "If Zero'd, uses random Stage spawn, otherwise spawns player at this position.\nDefault is relative to Hideout.\nWarning: Random can place you in closed OldHead areas.");
			BindConfig(worldEntry, "Seed", 0, "If Stage Random, and/or Spawn Random, uses this seed.\n0 = Fully Random Each Time");
			BindConfig(worldEntry, "Disable Story", defaultValue: false, "Disable Story Events such as Challenges.\nEnables Challenge Graffiti Pickups.");
			BindConfig(worldEntry, "Disable BMX Doors", defaultValue: false);
			BindConfig(worldEntry, "Enable Taxi Fight", defaultValue: true);
			BindConfig(worldEntry, "Enable Final Boss Trigger", defaultValue: false, "Enables the Trigger which lets you enter the Final Boss area, located at the start of the final Mataan area after the vent.\nOnly has an effect if Story is also enabled.");
			BindConfig(worldEntry, "Disable Cops", defaultValue: true);
			BindConfig(worldEntry, "Open Teleport Robo-Posts", defaultValue: true);
			BindConfig(worldEntry, "Allow Skipping All Cutscenes", defaultValue: true);
			BindConfig(worldEntry, "Fast Cutscene Skip", defaultValue: true);
			BindConfig(worldEntry, "Always Display REP", defaultValue: true);
			BindConfig(worldEntry, "Skip Mall Vinyl", defaultValue: true);
			bingoSyncEntry = new ConfigEntry(config_bingosync, "BingoSync");
			BindConfig(bingoSyncEntry, "Room ID", "", "Room ID (Numbers / Letters after /room/)");
			BindConfig(bingoSyncEntry, "Room Password", "", "Room Password");
			BindConfig(bingoSyncEntry, "Player Name", "", "Player Name in Room");
			BindConfig<PlayerColors>(bingoSyncEntry, "Player Color", (PlayerColors)1, "Player Color on Board");
			BindConfig(bingoSyncEntry, "Auto-Connect", defaultValue: true, "Auto-Connect if Config Found");
			BindConfig(bingoSyncEntry, "Notifications", defaultValue: true, "Show Phone notifications when someone gets something on the board");
			BindConfig<KeyCode>(bingoSyncEntry, "Menu Key", (KeyCode)282, "Key to Open Menu");
		}

		private static void BindConfig<T>(ConfigEntry configEntry, string key, T defaultValue, string description = "")
		{
			configEntry.configFile.Bind<T>(configEntry.selection, key, defaultValue, description);
		}

		public static void HandleConfig()
		{
			InitConfigs();
		}

		private static void ReloadConfigs()
		{
			config_char.Reload();
			config_world.Reload();
			config_bingosync.Reload();
			UpdateConfigAll();
		}

		private static void UpdateConfigAll()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if (characterEntry.TryGetEntry<BingoConfigTypes.Characters>("Character", out var entryValue))
			{
				character = BingoConfigTypes.GetCharacter(entryValue);
			}
			if (characterEntry.TryGetEntry<BingoConfigTypes.Styles>("Style", out var entryValue2))
			{
				moveStyle = BingoConfigTypes.GetStyle(entryValue2);
			}
			if (characterEntry.TryGetEntry<BingoConfigTypes.Outfits>("Outfit", out var entryValue3))
			{
				outfit = BingoConfigTypes.GetOutfit(entryValue3);
			}
			characterEntry.UpdateConfig("Seed", ref seed);
			if (worldEntry.TryGetEntry<BingoConfigTypes.Stages>("Starting Stage", out var entryValue4))
			{
				BingoConfigTypes.Stages stages = entryValue4;
				Random random = ((seed == 0) ? new Random() : new Random(seed));
				stage = BingoConfigTypes.GetStage((stages == BingoConfigTypes.Stages.Random) ? ((BingoConfigTypes.Stages)random.Next(7)) : stages);
			}
			worldEntry.UpdateConfig("Starting Position", ref position);
			worldEntry.UpdateConfig("Disable Story", ref disableStory);
			worldEntry.UpdateConfig("Disable BMX Doors", ref disableBMX);
			worldEntry.UpdateConfig("Enable Taxi Fight", ref enableTaxi);
			worldEntry.UpdateConfig("Enable Final Boss Trigger", ref enableBoss);
			worldEntry.UpdateConfig("Disable Cops", ref disableCops);
			worldEntry.UpdateConfig("Open Teleport Robo-Posts", ref roboSkip);
			worldEntry.UpdateConfig("Allow Skipping All Cutscenes", ref cutsceneSkip);
			worldEntry.UpdateConfig("Fast Cutscene Skip", ref fastCutscene);
			worldEntry.UpdateConfig("Always Display REP", ref repDisplay);
			worldEntry.UpdateConfig("Skip Mall Vinyl", ref skipMallVinyl);
			bingoSyncEntry.UpdateConfig("Auto-Connect", ref autoconnect);
			bingoSyncEntry.UpdateConfig("Notifications", ref phonenotification);
			bingoSyncEntry.UpdateConfig("Menu Key", ref menukey);
		}

		private static void UpdateConfig<T>(this ConfigEntry configEntry, string entry, ref T option)
		{
			if (configEntry.TryGetEntry<T>(entry, out var entryValue))
			{
				option = entryValue;
			}
		}

		public static void SetConfigValue<T>(this ConfigFile configEntry, string selection, string key, T value)
		{
			ConfigEntry<T> val = default(ConfigEntry<T>);
			if (configEntry.TryGetEntry<T>(selection, key, ref val))
			{
				val.Value = value;
			}
			configEntry.Save();
		}

		private static bool TryGetEntry<T>(this ConfigEntry configEntry, string key, out T entryValue)
		{
			ConfigEntry<T> val = default(ConfigEntry<T>);
			if (configEntry.configFile.TryGetEntry<T>(configEntry.selection, key, ref val))
			{
				entryValue = val.Value;
				return true;
			}
			entryValue = default(T);
			return false;
		}
	}
	public static class BingoConfigTypes
	{
		public enum Outfits
		{
			Spring,
			Summer,
			Autumn,
			Winter
		}

		public enum Styles
		{
			Skateboard,
			Inline,
			BMX
		}

		public enum Characters
		{
			Vinyl,
			Frank,
			Coil,
			Red,
			Tryce,
			Bel,
			Rave,
			DOTEXE,
			Solace,
			DJCyber,
			Eclipse,
			DevilTheory,
			Faux,
			FleshPrince,
			Irene,
			Felix,
			OldHead,
			Base,
			Jay,
			Mesh,
			Futurism,
			Rise,
			Shine,
			Faux_NoJetpack,
			DOTEXE_Boss,
			Felix_Red
		}

		public enum Stages
		{
			Hideout,
			Versum,
			Square,
			Brink,
			Mall,
			Pyramid,
			Mataan,
			Random
		}

		public static Characters GetCharacter(Characters character)
		{
			return (Characters)character;
		}

		public static MoveStyle GetStyle(Styles style)
		{
			return (MoveStyle)(style switch
			{
				Styles.Skateboard => 2, 
				Styles.Inline => 3, 
				Styles.BMX => 1, 
				_ => 2, 
			});
		}

		public static int GetOutfit(Outfits outfit)
		{
			return (int)outfit;
		}

		public static Stage GetStage(Stages stage)
		{
			return (Stage)(stage switch
			{
				Stages.Hideout => 5, 
				Stages.Versum => 4, 
				Stages.Square => 11, 
				Stages.Brink => 12, 
				Stages.Mall => 6, 
				Stages.Pyramid => 9, 
				Stages.Mataan => 7, 
				_ => 5, 
			});
		}
	}
	public static class BingoHandleStage
	{
		public static bool HasLeftRespawn = false;

		public static Vector3 spawnPosition = Vector3.zero;

		public static void UpdateStage()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Stage currentStage = Utility.GetCurrentStage();
			WorldHandler instance = WorldHandler.instance;
			SceneObjectsRegister sceneObjectsRegister = ((instance != null) ? instance.SceneObjectsRegister : null);
			WorldHandler instance2 = WorldHandler.instance;
			Player player = ((instance2 != null) ? instance2.GetCurrentPlayer() : null);
			BingoConfig.HandleConfig();
			UpdateObjective();
			UpdatePlayer(player);
			if (Patch_NewGame.newGame)
			{
				HandleNewGame(instance2, player);
			}
			UpdateProgress(sceneObjectsRegister, currentStage);
			UpdateStageProgress(sceneObjectsRegister, currentStage);
			if (BingoConfig.disableBMX)
			{
				DisableBMXDoors();
			}
			if (BingoConfig.roboSkip)
			{
				UnlockRoboDoors();
			}
		}

		private static void UpdatePlayer(Player player)
		{
			Core instance = Core.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			SaveSlotData val = (SaveSlotData)obj;
			if (val != null)
			{
				val.taxiLocked = false;
				if (((Ability)player.GetValue<AirDashAbility>("airDashAbility", Array.Empty<object>())).locked || ((Ability)player.GetValue<SlideAbility>("slideAbility", Array.Empty<object>())).locked || ((Ability)player.GetValue<SpecialAirAbility>("specialAirAbility", Array.Empty<object>())).locked || ((Ability)player.GetValue<LedgeClimbAbility>("ledgeClimbAbility", Array.Empty<object>())).locked || ((Ability)player.GetValue<BoostAbility>("boostAbility", Array.Empty<object>())).locked || val.boostAbilityLocked || val.boostpackLocked)
				{
					player.LockBoostpack(false);
				}
				if (val.cameraAppLocked)
				{
					player.LockCameraApp(false);
				}
				if (val.characterSelectLocked)
				{
					player.LockCharacterSelect(false);
				}
				if (val.phoneLocked)
				{
					player.LockPhone(false);
				}
				if (val.spraycanLocked)
				{
					player.LockSpraycan(false);
				}
				if (val.switchToEquippedMovestyleLocked)
				{
					player.LockSwitchToEquippedMoveStyle(false);
				}
				if (!val.fortuneAppLocked)
				{
					player.LockFortuneApp(true);
				}
				UnlockVinylSolace(val);
			}
		}

		private static void UnlockVinylSolace(SaveSlotData saveSlot)
		{
			if (saveSlot != null)
			{
				if (!saveSlot.GetCharacterProgress((Characters)0).unlocked)
				{
					saveSlot.UnlockCharacter((Characters)0);
				}
				if (!saveSlot.GetCharacterProgress((Characters)8).unlocked)
				{
					saveSlot.UnlockCharacter((Characters)8);
				}
			}
		}

		private static void HandleNewGame(WorldHandler worldHandler, Player player)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			Patch_NewGame.newGame = false;
			if (!((Object)(object)player != (Object)null))
			{
				return;
			}
			Core instance = Core.Instance;
			SaveManager val = ((instance != null) ? instance.SaveManager : null);
			player.SetCharacter(BingoConfig.character, 0);
			player.InitVisual();
			player.SetCurrentMoveStyleEquipped(BingoConfig.moveStyle, true, true);
			player.InitAbilities();
			player.GetValue<CharacterVisual>("characterVisual", Array.Empty<object>()).SetMoveStyleVisualProps(player, BingoConfig.moveStyle, false);
			player.SwitchToEquippedMovestyle(false, false, true, false);
			if (((val != null) ? val.CurrentSaveSlot : null) != null)
			{
				val.CurrentSaveSlot.GetCharacterProgress(BingoConfig.character).moveStyle = BingoConfig.moveStyle;
			}
			player.SetOutfit(BingoConfig.outfit);
			if (val != null)
			{
				SaveSlotData currentSaveSlot = val.CurrentSaveSlot;
				if (currentSaveSlot != null)
				{
					currentSaveSlot.SetupStoryCharactersLocked();
				}
			}
			UnlockVinylSolace(val.CurrentSaveSlot);
			for (int i = 0; i < 6; i++)
			{
				if (val != null)
				{
					SaveSlotData currentSaveSlot2 = val.CurrentSaveSlot;
					if (currentSaveSlot2 != null)
					{
						currentSaveSlot2.UnlockDance(i);
					}
				}
			}
			spawnPosition = BingoConfig.position;
			Quaternion rotation = ((Component)player).transform.rotation;
			if (spawnPosition == Vector3.zero)
			{
				List<PlayerSpawner> list = worldHandler.SceneObjectsRegister?.playerSpawners;
				Random random = ((BingoConfig.seed == 0) ? new Random() : new Random(BingoConfig.seed));
				if (list.Count > 0)
				{
					PlayerSpawner obj = list[random.Next(list.Count)];
					spawnPosition = ((Component)obj).transform.position;
					rotation = ((Component)obj).transform.rotation;
				}
			}
			worldHandler.PlaceCurrentPlayerAt(spawnPosition, rotation, true);
			HasLeftRespawn = false;
			val.SaveCurrentSaveSlot();
		}

		private static void UpdateProgress(SceneObjectsRegister sceneObjectsRegister, Stage stage)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Invalid comparison between Unknown and I4
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Invalid comparison between Unknown and I4
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Invalid comparison between Unknown and I4
			if (sceneObjectsRegister == null)
			{
				return;
			}
			List<ProgressObject> progressObjects = sceneObjectsRegister.progressObjects;
			if (BingoConfig.disableStory)
			{
				foreach (Collectable item in from x in Resources.FindObjectsOfTypeAll<Collectable>()
					where (int)x.GetValue<PickUpType>("pickUpType", Array.Empty<object>()) == 4
					select x)
				{
					((GameplayEvent)item).canOpen = true;
					item.InvokeMethod("SetAvailable", true);
				}
			}
			if (progressObjects == null)
			{
				return;
			}
			ProgressObject[] array = (ProgressObject[])(object)new ProgressObject[0];
			ProgressObject[] array2 = progressObjects.Where((ProgressObject x) => BingoStageItems.GlobalProgressObjects.Contains(((Object)x).name)).ToArray();
			if ((int)stage != 4)
			{
				if ((int)stage != 5)
				{
					if ((int)stage == 11)
					{
						array = progressObjects.Where((ProgressObject x) => BingoStageItems.SquareProgressObjects.Contains(((Object)x).name)).ToArray();
					}
				}
				else
				{
					array = progressObjects.Where((ProgressObject x) => BingoStageItems.HideoutProgressObjects.Contains(((Object)x).name)).ToArray();
				}
			}
			else
			{
				array = progressObjects.Where((ProgressObject x) => BingoStageItems.DownhillProgressObjects.Contains(((Object)x).name)).ToArray();
			}
			ProgressObject[] array3 = array;
			for (int i = 0; i < array3.Length; i++)
			{
				((Component)array3[i]).gameObject.SetActive(false);
			}
			array3 = array2;
			foreach (ProgressObject obj in array3)
			{
				((Component)obj).gameObject.SetActive(true);
				obj.SetAvailable(true);
				obj.SetTriggerable(true);
			}
		}

		private static void DisableBMXDoors()
		{
			BMXOnlyGateway val = Object.FindObjectOfType<BMXOnlyGateway>();
			if ((Object)(object)val != (Object)null)
			{
				val.InvokeMethod("SetState", 5);
			}
		}

		public static void UpdateObjective()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			ObjectiveID val = (ObjectiveID)14;
			Core instance = Core.Instance;
			SaveManager val2 = ((instance != null) ? instance.SaveManager : null);
			if (((val2 != null) ? val2.CurrentSaveSlot : null) != null && val2.CurrentSaveSlot.CurrentStoryObjective != val)
			{
				val2.CurrentSaveSlot.CurrentStoryObjective = val;
				val2.SaveCurrentSaveSlot();
				Mapcontroller instance2 = Mapcontroller.Instance;
				if (instance2 != null)
				{
					instance2.UpdateObjectivePins();
				}
			}
		}

		public static void UpdateWanted()
		{
			if (BingoConfig.disableCops)
			{
				WantedManager instance = WantedManager.instance;
				if (instance != null)
				{
					instance.StopPlayerWantedStatus(false);
				}
			}
		}

		public static void UpdateStageProgress(SceneObjectsRegister sceneObjectsRegister, Stage stage)
		{
			//IL_005f: 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_008b: Expected I4, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Expected O, but got Unknown
			List<AProgressable> list = sceneObjectsRegister?.progressables;
			if (list == null)
			{
				return;
			}
			AProgressable val = list.Find((AProgressable x) => BingoStageItems.PostGameChallenges.Contains(((Object)x).name));
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(true);
			}
			AProgressable[] array = (AProgressable[])(object)new AProgressable[0];
			AProgressable[] array2 = (AProgressable[])(object)new AProgressable[0];
			AProgressable val2 = null;
			switch (stage - 4)
			{
			case 8:
				array = list.Where((AProgressable x) => BingoStageItems.TowerAProgressable_Disable.Contains(((Object)x).name)).ToArray();
				array2 = list.Where((AProgressable x) => BingoStageItems.TowerAProgressable_Enable.Contains(((Object)x).name)).ToArray();
				break;
			case 7:
				if (!BingoConfig.enableTaxi)
				{
					array = list.Where((AProgressable x) => BingoStageItems.SquareAProgressable_Disable.Contains(((Object)x).name)).ToArray();
				}
				array2 = list.Where((AProgressable x) => BingoStageItems.SquareAProgressable_Enable.Contains(((Object)x).name)).ToArray();
				if (array2.Length != 0)
				{
					AProgressable val4 = ((IEnumerable<AProgressable>)array2).FirstOrDefault((Func<AProgressable, bool>)((AProgressable x) => ((Object)x).name == BingoStageItems.SquareAProgressable_Enable[0]));
					if ((Object)(object)val4 != (Object)null)
					{
						((GraffitiSpot)((val4 is GraffitiSpot) ? val4 : null)).OnFinish = new UnityEvent();
					}
				}
				break;
			case 3:
				array = list.Where((AProgressable x) => BingoStageItems.OsakaAProgressable_Disable.Contains(((Object)x).name) || (!BingoConfig.enableBoss && BingoStageItems.OsakaBoss_Disable.Contains(((Object)x).name))).ToArray();
				array2 = list.Where((AProgressable x) => BingoStageItems.OsakaAProgressable_Enable.Contains(((Object)x).name)).ToArray();
				break;
			case 2:
				array = list.Where((AProgressable x) => BingoStageItems.MallAProgressable_Disable.Contains(((Object)x).name)).ToArray();
				HandleMallVinyl();
				break;
			case 5:
				array = list.Where((AProgressable x) => BingoStageItems.PyramidAProgressable_Disable.Contains(((Object)x).name)).ToArray();
				array2 = list.Where((AProgressable x) => BingoStageItems.PyramidAProgressable_Enable.Contains(((Object)x).name)).ToArray();
				break;
			case 0:
			{
				Core instance = Core.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					SaveManager saveManager = instance.SaveManager;
					obj = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
				}
				SaveSlotData val3 = (SaveSlotData)obj;
				if (val3 != null && !val3.GetCharacterProgress((Characters)14).unlocked)
				{
					val2 = list.Find((AProgressable x) => ((Object)x).name == "CombatEncounter_IreneUnlockChallenge");
					if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject.GetComponent<Component_IreneTrigger>() == (Object)null)
					{
						((Component)val2).gameObject.AddComponent<Component_IreneTrigger>();
					}
				}
				break;
			}
			}
			AProgressable[] array3 = array;
			for (int i = 0; i < array3.Length; i++)
			{
				((Component)array3[i]).gameObject.SetActive(false);
			}
			array3 = array2;
			for (int i = 0; i < array3.Length; i++)
			{
				((Component)array3[i]).gameObject.SetActive(true);
			}
		}

		private static void HandleMallVinyl()
		{
			if (BingoConfig.skipMallVinyl)
			{
				BoxCollider[] array = (from x in Resources.FindObjectsOfTypeAll<BoxCollider>()
					where ((Object)x).name == "ProgressObject_TriggerIntro" || ((Object)x).name == "NPC_Vinyl1"
					select x).ToArray();
				for (int i = 0; i < array.Length; i++)
				{
					((Component)array[i]).gameObject.SetActive(false);
				}
				NPC val = ((IEnumerable<NPC>)Resources.FindObjectsOfTypeAll<NPC>()).FirstOrDefault((Func<NPC, bool>)((NPC x) => ((Object)x).name == "NPC_Vinyl4"));
				if ((Object)(object)val != (Object)null && val.GetValue<int>("dialogueLevel", Array.Empty<object>()) < 1)
				{
					val.InvokeMethod("SetNPCActive", true);
					val.InvokeMethod("SetAvailable", true);
					val.SetDialogueLevel(1);
				}
			}
		}

		public static void UnlockRoboDoors()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0009: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected I4, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			Stage currentStage = Utility.GetCurrentStage();
			if ((int)currentStage != 9 && (int)currentStage != 6 && (int)currentStage != 7)
			{
				return;
			}
			ComboMascotSystem[] array = Object.FindObjectsOfType<ComboMascotSystem>().ToArray();
			if ((((int)currentStage == 9 || (int)currentStage == 6) && array.Length > 1) || ((int)currentStage == 7 && array.Length != 0))
			{
				ComboMascotSystem val = null;
				switch (currentStage - 6)
				{
				case 0:
				case 3:
					val = array[1];
					break;
				case 1:
					val = array[0];
					break;
				}
				if ((Object)(object)val != (Object)null)
				{
					val.door1.MakeUnactive();
					val.door2.MakeUnactive();
					val.TurnOffMascots();
				}
			}
		}
	}
	public static class BingoStageItems
	{
		public static readonly string[] HideoutProgressObjects = new string[5] { "GarageDoorBMXClosed", "GarageDoorInlineClosed", "SquareWall", "GateOsaka", "GarageDoorSBClosed" };

		public static readonly string[] DownhillProgressObjects = new string[9] { "ProgressObject_basketWallToSquare", "ProgressObject_ForceTalkToBel", "ProgressObject_basketWallWithCars", "ProgressObject_basketWall2Gate", "ProgressObject_basketWall2", "FranksIntroTrigger", "BarricadeExit", "FranksBarricadeChunks1", "BarricadeChunks1" };

		public static readonly string[] SquareProgressObjects = new string[4] { "ProgressObject_SolaceTrigger", "Wall", "ProgressObject_SquareIntro_1", "ProgressObject_SquareIntro_2" };

		public static readonly string[] GlobalProgressObjects = new string[6] { "AllGraffitiProgressObject", "collectables_Hideout", "ProgressObject_MapPickup", "ProgressObject_MapUnlockPickup", "ProgressObject_Map_Pickup", "ProgressObject_MapUnlock" };

		public static readonly string[] TowerAProgressable_Disable = new string[2] { "ProgressObject_WallToTower", "ProgressObject_TowerDoor" };

		public static readonly string[] TowerAProgressable_Enable = new string[1] { "ProgressObject_FrankGraffiti" };

		public static readonly string[] SquareAProgressable_Disable = new string[3] { "SaveTaxiDriverCops", "NPC_TaxiDriver", "SaveTaxiDriverCombatEncounter" };

		public static readonly string[] SquareAProgressable_Enable = new string[1] { "FrankGraffiti" };

		public static readonly string[] OsakaAProgressable_Disable = new string[4] { "ProgressObject_StartTrigger", "LionStatueModelClosed", "ProgressObject_Gate", "ProgressObjectGateArena" };

		public static readonly string[] OsakaBoss_Disable = new string[1] { "IntroSnakeBoss" };

		public static readonly string[] OsakaAProgressable_Enable = new string[1] { "LionStatueModelOpen" };

		public static readonly string[] MallAProgressable_Disable = new string[3] { "ProgressObject_HallwayDoor", "ProgressObject_FirstProgressDoor", "ProgressObject_SecondProgressDoor" };

		public static readonly string[] PyramidAProgressable_Disable = new string[3] { "ProgressObject_DoorOutOfLab", "REPdoor", "ProgressObject_DoorToHigherAreas" };

		public static readonly string[] PyramidAProgressable_Enable = new string[1] { "ProgressObject_FerriesToIsland" };

		public static readonly string[] PostGameChallenges = new string[6] { "NPC_Eclipe_UnlockChallenge", "NPC_DJ_UnlockChallenge", "NPC_Futurism_UnlockChallenge", "NPC_DOTEXE_UnlockChallenge", "NPC_DevilTheory_UnlockChallenge", "NPC_Frank_UnlockChallenge" };
	}
	public static class Extensions
	{
		private static BindingFlags flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static List<MemberInfo> savedMembers = new List<MemberInfo>();

		public static T GetValue<T>(this object input, string name, params object[] methodParams)
		{
			if (input.GetMember(name, out var member))
			{
				switch (member.MemberType)
				{
				case MemberTypes.Field:
					return (T)(member as FieldInfo).GetValue(input);
				case MemberTypes.Property:
					return (T)(member as PropertyInfo).GetValue(input, null);
				case MemberTypes.Method:
					return (T)(member as MethodInfo).Invoke(input, methodParams);
				}
			}
			return default(T);
		}

		public static void InvokeMethod(this object input, string name, params object[] methodParams)
		{
			if (input.GetMember(name, out var member))
			{
				(member as MethodInfo).Invoke(input, methodParams);
			}
		}

		public static void SetValue<T>(this object input, string name, T value)
		{
			if (input.GetMember(name, out var member))
			{
				switch (member.MemberType)
				{
				case MemberTypes.Field:
					(member as FieldInfo).SetValue(input, value);
					break;
				case MemberTypes.Property:
					(member as PropertyInfo).SetValue(input, value);
					break;
				}
			}
		}

		public static T GetMember<T>(this object input, string name) where T : MemberInfo
		{
			if (input.GetMember(name, out var member))
			{
				return (T)member;
			}
			return null;
		}

		private static bool GetMember(this object input, string name, out MemberInfo member)
		{
			MemberInfo memberInfo = savedMembers.Find((MemberInfo x) => x.DeclaringType == input.GetType() && x.Name == name);
			if (memberInfo != null)
			{
				member = memberInfo;
				return true;
			}
			MemberInfo[] member2 = input.GetType().GetMember(name, flags);
			if (member2 != null && member2.Length != 0)
			{
				member = member2.First();
				savedMembers.Add(member);
				return true;
			}
			Debug.LogError((object)("No Member \"" + name + "\" Could Be Found..."));
			member = null;
			return false;
		}
	}
	[BepInPlugin("ninjacookie.brc.truebingo", "TrueBingo", "1.2.4")]
	public class Plugin : BaseUnityPlugin
	{
		public const string pluginGuid = "ninjacookie.brc.truebingo";

		public const string pluginName = "TrueBingo";

		public const string pluginVersion = "1.2.4";

		public static GameObject BingoSyncGUI;

		public void Awake()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			new Harmony("ninjacookie.brc.truebingo").PatchAll();
			BingoConfig.InitConfigs();
			StageManager.OnStageInitialized += new OnStageInitializedDelegate(BingoHandleStage.UpdateStage);
			Core.OnUpdate += new OnUpdateHandler(BingoHandleStage.UpdateObjective);
			Core.OnUpdate += new OnUpdateHandler(BingoHandleStage.UpdateWanted);
			Core.OnAlwaysUpdate += new OnUpdateHandler(TrueBingoSync.Update);
			BingoSyncGUI = new GameObject("BingoSyncGUI", new Type[1] { typeof(BingoSyncGUI) });
			Object.DontDestroyOnLoad((Object)(object)BingoSyncGUI);
		}
	}
}
namespace TrueBingo.Patches
{
	internal class Patch_CutsceneSkip : HarmonyPatch
	{
		[HarmonyPatch(typeof(SequenceHandler), "UpdateSequenceHandler")]
		public static class UpdateSequenceHandler_Patch
		{
			public static void Prefix(SequenceHandler __instance, Player ___player, PlayableDirector ___sequence, ref float ___skipFadeDuration, ref float ___skipStartTimer)
			{
				if (BingoConfig.fastCutscene)
				{
					___skipFadeDuration = 0f;
					___skipStartTimer = 1.5f;
				}
				if (BingoConfig.cutsceneSkip && (Object)(object)___player != (Object)null && ___player.IsBusyWithSequence() && (Object)(object)___sequence != (Object)null && !((object)___sequence).ToString().Contains("ChangeOutfitSequence") && __instance.GetValue<int>("skipTextActiveState", Array.Empty<object>()) == 0)
				{
					__instance.SetValue("skipTextActiveState", 1);
				}
			}
		}
	}
	internal class Patch_Inputs : HarmonyPatch
	{
		[HarmonyPatch(typeof(UserInputHandler), "PollInputs")]
		public static class UserInputHandler_PollInputs_Patch
		{
			public static bool Prefix(ref InputBuffer __result)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				if (BingoSyncGUI.GUIOpen)
				{
					__result = default(InputBuffer);
					return false;
				}
				return true;
			}
		}
	}
	internal class Patch_ItemDisplay : HarmonyPatch
	{
		[HarmonyPatch(typeof(Pickup), "ApplyPickupType")]
		public static class Pickup_ApplyPickupType_Patch
		{
			public static void Prefix(AUnlockable unlockable, PickUpType pickupType)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Invalid comparison between Unknown and I4
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				if ((int)pickupType != 5)
				{
					return;
				}
				OutfitUnlockable val = (OutfitUnlockable)(object)((unlockable is OutfitUnlockable) ? unlockable : null);
				if ((Object)(object)val != (Object)null)
				{
					Core instance = Core.Instance;
					object charName;
					if (instance == null)
					{
						charName = null;
					}
					else
					{
						IGameTextLocalizer localizer = instance.Localizer;
						charName = ((localizer != null) ? localizer.GetCharacterName(val.character) : null);
					}
					Patch_ItemDisplay.charName = (string)charName;
				}
			}
		}

		[HarmonyPatch(typeof(UIManager), "ShowNotification", new Type[]
		{
			typeof(string),
			typeof(string[])
		})]
		public static class UIManager_ShowNotification_Patch
		{
			public static void Prefix(ref string text, params string[] textsToInsert)
			{
				if (!(charName != string.Empty))
				{
					return;
				}
				int num = textsToInsert.Count();
				if (num > 0)
				{
					for (int i = 0; i < num; i++)
					{
						if (textsToInsert[i].Equals("???"))
						{
							textsToInsert[i] = charName;
							break;
						}
					}
				}
				charName = string.Empty;
			}
		}

		private static string charName = string.Empty;
	}
	internal class Patch_LegalCrime : HarmonyPatch
	{
		[HarmonyPatch(typeof(WantedManager), "ProcessCrime")]
		public static class ProcessCrime_Patch
		{
			public static bool Prefix()
			{
				return !BingoConfig.disableCops;
			}
		}
	}
	internal class Patch_NewGame : HarmonyPatch
	{
		[HarmonyPatch(typeof(BaseModule), "StartNewGame")]
		public static class BaseModule_StartNewGame_Patch
		{
			public static bool Prefix(BaseModule __instance)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				newGame = true;
				BingoConfig.HandleConfig();
				__instance.LoadStage(BingoConfig.stage);
				return false;
			}
		}

		[HarmonyPatch(typeof(ActiveOnChapter), "OnStageInitialized")]
		public static class ActiveOnChapter_OnStageInitialized_Patch
		{
			public static void Prefix()
			{
				WorldHandler instance = WorldHandler.instance;
				if (instance != null)
				{
					StoryManager storyManager = instance.StoryManager;
					if (storyManager != null)
					{
						storyManager.SetStoryObjective((ObjectiveID)14);
					}
				}
			}

			public static void Postfix(ActiveOnChapter __instance)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Invalid comparison between Unknown and I4
				if ((int)Utility.GetCurrentStage() != 5)
				{
					((Component)__instance).gameObject.SetActive((!BingoConfig.disableStory || __instance.chapters.Contains((Chapter)6)) && ((Object)__instance).name != "BeforeFinalBossElephants");
				}
				else
				{
					((Component)__instance).gameObject.SetActive(false);
				}
			}
		}

		[HarmonyPatch(typeof(BaseModule), "HandleStageFullyLoaded")]
		public static class BaseModule_HandleStageFullyLoaded_Patch
		{
			public static void Postfix()
			{
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				Core instance = Core.Instance;
				SaveManager val = ((instance != null) ? instance.SaveManager : null);
				WorldHandler instance2 = WorldHandler.instance;
				Player val2 = ((instance2 != null) ? instance2.GetCurrentPlayer() : null);
				if ((Object)(object)val2 != (Object)null && ((val != null) ? val.CurrentSaveSlot : null) != null)
				{
					Stage currentStage = Utility.GetCurrentStage();
					val.CurrentSaveSlot.GetStageProgress(currentStage).respawnPos = ((Component)val2).transform.position;
					StageProgress stageProgress = val.CurrentSaveSlot.GetStageProgress(currentStage);
					Quaternion rotation = ((Component)val2).transform.rotation;
					stageProgress.respawnRot = ((Quaternion)(ref rotation)).eulerAngles;
					val.SaveCurrentSaveSlotImmediate();
				}
				BingoHandleStage.UpdateStageProgress((instance2 != null) ? instance2.SceneObjectsRegister : null, Utility.GetCurrentStage());
			}
		}

		[HarmonyPatch(typeof(WorldHandler), "SavePosToNearestReachedRespawner")]
		public static class WorldHandler_SavePosToNearestReachedRespawner_Patch
		{
			public static bool Prefix(WorldHandler __instance)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				if (!BingoHandleStage.HasLeftRespawn)
				{
					Player currentPlayer = __instance.GetCurrentPlayer();
					if ((Object)(object)currentPlayer != (Object)null)
					{
						if (Vector3.Distance(((Component)currentPlayer).transform.position, BingoHandleStage.spawnPosition) > 2f)
						{
							BingoHandleStage.HasLeftRespawn = true;
							return true;
						}
						return false;
					}
				}
				return true;
			}
		}

		public static bool newGame;
	}
	internal class Patch_NPCAvailability : HarmonyPatch
	{
		[HarmonyPatch(typeof(WorldHandler), "SetNPCAvailabilityBasedOnPlayer")]
		public static class WorldHandler_SetNPCAvailabilityBasedOnPlayer_Patch
		{
			public static bool Prefix(SceneObjectsRegister ___sceneObjectsRegister)
			{
				EnableNPCs(___sceneObjectsRegister);
				return false;
			}
		}

		[HarmonyPatch(typeof(WorldHandler), "SetNPCAvailabilityBasedOnCharacter")]
		public static class WorldHandler_SetNPCAvailabilityBasedOnCharacter_Patch
		{
			public static bool Prefix(SceneObjectsRegister ___sceneObjectsRegister)
			{
				EnableNPCs(___sceneObjectsRegister);
				return false;
			}
		}

		[HarmonyPatch(typeof(WorldHandler), "SetNPCAvailabilityBasedOnCharacterSelect")]
		public static class WorldHandler_SetNPCAvailabilityBasedOnCharacterSelect_Patch
		{
			public static bool Prefix(SceneObjectsRegister ___sceneObjectsRegister)
			{
				EnableNPCs(___sceneObjectsRegister);
				return false;
			}
		}

		[HarmonyPatch(typeof(WorldHandler), "CharacterIsAlreadyNPCInScene")]
		public static class WorldHandler_CharacterIsAlreadyNPCInScene_Patch
		{
			public static bool Prefix(ref bool __result)
			{
				__result = false;
				return false;
			}
		}

		public static void EnableNPCs(SceneObjectsRegister sceneObjectsRegister)
		{
			foreach (NPC nPC in sceneObjectsRegister.NPCs)
			{
				nPC.InvokeMethod("SetAvailable", true);
			}
		}
	}
	internal class Patch_RepLabel : HarmonyPatch
	{
		[HarmonyPatch(typeof(Player), "SetRepLabel")]
		public static class Player_SetRepLabel_Patch
		{
			public static bool Prefix(GameplayUI ___ui)
			{
				if (!BingoConfig.repDisplay)
				{
					return true;
				}
				Core instance = Core.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					SaveManager saveManager = instance.SaveManager;
					if (saveManager == null)
					{
						obj = null;
					}
					else
					{
						SaveSlotData currentSaveSlot = saveManager.CurrentSaveSlot;
						obj = ((currentSaveSlot != null) ? currentSaveSlot.GetCurrentStageProgress() : null);
					}
				}
				StageProgress val = (StageProgress)obj;
				if (val != null)
				{
					((TMP_Text)___ui.repLabel).text = val.reputation.ToString();
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Player), "RepDisplayUpdate")]
		public static class Player_RepDisplayUpdate_Patch
		{
			public static bool Prefix(ref float ___showRepLingerTimer, ref int ___showAddRep, ref float ___showingREP)
			{
				if (!BingoConfig.repDisplay)
				{
					return true;
				}
				___showRepLingerTimer = 99f;
				___showAddRep = 0;
				___showingREP = -1f;
				return true;
			}
		}
	}
	internal class Patch_BingoSync : HarmonyPatch
	{
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static class Pickup_ApplyPickupType_Patch
		{
			public static void Postfix(AUnlockable unlockable, PickUpType pickupType)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected I4, but got Unknown
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Invalid comparison between Unknown and I4
				//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
				if ((int)TrueBingoSync.bingoSync.Status != 0)
				{
					return;
				}
				string text = string.Empty;
				switch (pickupType - 3)
				{
				default:
					if ((int)pickupType == 11)
					{
						text = English.GetSkinText(((MoveStyleSkin)((unlockable is MoveStyleSkin) ? unlockable : null)).Title, Array.Empty<string>());
					}
					break;
				case 0:
					text = ((MusicTrack)((unlockable is MusicTrack) ? unlockable : null)).Title;
					break;
				case 1:
					text = ((GraffitiAppEntry)((unlockable is GraffitiAppEntry) ? unlockable : null)).Title;
					break;
				case 2:
				{
					if (HardCharNames.TryGetValue(((OutfitUnlockable)((unlockable is OutfitUnlockable) ? unlockable : null)).character, out var value))
					{
						text = StringExtensions.FirstCharToUpper(value.ToLower()) + ": " + English.GetSkinText(((OutfitUnlockable)((unlockable is OutfitUnlockable) ? unlockable : null)).outfitName, Array.Empty<string>());
					}
					break;
				}
				}
				if (text != string.Empty)
				{
					MarkObjective(text, TrueBingoSync.ObjectiveType.ItemPickup, pickupType);
				}
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static class SaveSlotData_UnlockCharacter_Patch
		{
			public static void Postfix(Characters character)
			{
				//IL_0005: 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)
				if ((int)TrueBingoSync.bingoSync.Status == 0)
				{
					MarkObjective(StringExtensions.FirstCharToUpper(English.GetCharacterName(character).ToLower()), TrueBingoSync.ObjectiveType.CharacterUnlock);
				}
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static class NPC_UnlockTaxi_Patch
		{
			public static void Postfix()
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				if ((int)TrueBingoSync.bingoSync.Status == 0)
				{
					MarkObjective("Save the Taxi Driver", TrueBingoSync.ObjectiveType.TaxiDriver);
				}
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static class StageProgress_AddRep_Patch
		{
			public static void Postfix(int ___reputation, Stage ___stageID)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Expected I4, but got Unknown
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				if ((int)TrueBingoSync.bingoSync.Status == 0)
				{
					int num = 999;
					switch (___stageID - 4)
					{
					case 0:
					case 8:
						num = 142;
						break;
					case 1:
						num = 108;
						break;
					case 7:
						num = 107;
						break;
					case 2:
					case 5:
						num = 148;
						break;
					case 3:
						num = 184;
						break;
					}
					if (___reputation >= num)
					{
						MarkObjective(English.GetStageName(___stageID), TrueBingoSync.ObjectiveType.Rep);
					}
				}
			}
		}

		private static readonly IGameTextLocalizer English = (IGameTextLocalizer)new TextMeshProGameTextLocalizer((SystemLanguage)10, (SystemLanguage)10, Core.Instance.localizerData, Core.Instance.platformData.languageData, Core.Instance.platformData.buttonSpriteData, Core.Instance.GameInput);

		public static Dictionary<Characters, string> HardCharNames = new Dictionary<Characters, string>
		{
			{
				(Characters)0,
				"VINYL"
			},
			{
				(Characters)1,
				"FRANK"
			},
			{
				(Characters)2,
				"COIL"
			},
			{
				(Characters)3,
				"RED"
			},
			{
				(Characters)4,
				"TRYCE"
			},
			{
				(Characters)5,
				"BEL"
			},
			{
				(Characters)6,
				"RAVE"
			},
			{
				(Characters)7,
				"DOT EXE"
			},
			{
				(Characters)8,
				"SOLACE"
			},
			{
				(Characters)9,
				"DJ CYBER"
			},
			{
				(Characters)10,
				"ECLIPSE"
			},
			{
				(Characters)11,
				"DEVIL THEORY"
			},
			{
				(Characters)12,
				"FAUX"
			},
			{
				(Characters)13,
				"FLESH PRINCE"
			},
			{
				(Characters)14,
				"RIETVELD"
			},
			{
				(Characters)15,
				"FELIX"
			},
			{
				(Characters)16,
				"OLDHEAD"
			},
			{
				(Characters)17,
				"BASE"
			},
			{
				(Characters)18,
				"JAY"
			},
			{
				(Characters)19,
				"MESH"
			},
			{
				(Characters)20,
				"FUTURISM"
			},
			{
				(Characters)21,
				"RISE"
			},
			{
				(Characters)22,
				"SHINE"
			},
			{
				(Characters)23,
				"FAUX"
			},
			{
				(Characters)24,
				"DOT EXE"
			},
			{
				(Characters)25,
				"RED FELIX"
			}
		};

		private static void MarkObjective(string itemToSend, TrueBingoSync.ObjectiveType objectiveType, PickUpType? pickupType = null)
		{
			TrueBingoSync.MarkObjective(itemToSend, objectiveType, pickupType);
		}
	}
}
namespace TrueBingo.Components
{
	internal class Component_IreneTrigger : MonoBehaviour
	{
		private ProgressObject BackToPrinceTrigger;

		private ProgressObject ProgressObject_Bel;

		private ProgressObject ProgressObject_AmbushEnemies;

		private WorldHandler worldHandler;

		private Player player;

		private SaveSlotData saveSlotData;

		private Encounter encounter;

		private const string encounterName = "CombatEncounter_IreneUnlockChallenge";

		private bool ShouldBeActive
		{
			get
			{
				if (!BackToPrinceTrigger.isActive && !ProgressObject_Bel.isActive && (Object)(object)encounter == (Object)null)
				{
					return !player.IsBusyWithSequence();
				}
				return false;
			}
		}

		public void Awake()
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			worldHandler = WorldHandler.instance;
			WorldHandler obj = worldHandler;
			player = ((obj != null) ? obj.GetCurrentPlayer() : null);
			Core instance = Core.Instance;
			object obj2;
			if (instance == null)
			{
				obj2 = null;
			}
			else
			{
				SaveManager saveManager = instance.SaveManager;
				obj2 = ((saveManager != null) ? saveManager.CurrentSaveSlot : null);
			}
			saveSlotData = (SaveSlotData)obj2;
			WorldHandler instance2 = WorldHandler.instance;
			List<ProgressObject> list = ((instance2 == null) ? null : instance2.SceneObjectsRegister?.progressObjects);
			if (list != null)
			{
				BackToPrinceTrigger = list.Find((ProgressObject x) => ((Object)x).name == "BackToPrinceTrigger");
				ProgressObject_Bel = list.Find((ProgressObject x) => ((Object)x).name == "ProgressObject_Bel");
				ProgressObject_AmbushEnemies = list.Find((ProgressObject x) => ((Object)x).name == "ProgressObject_AmbushEnemies");
			}
			Core.OnAlwaysUpdate += new OnUpdateHandler(CheckShouldBeActive);
		}

		public void CheckShouldBeActive()
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			if (saveSlotData != null)
			{
				bool unlocked = saveSlotData.GetCharacterProgress((Characters)14).unlocked;
				if (!unlocked && (Object)(object)worldHandler != (Object)null && (Object)(object)player != (Object)null && (Object)(object)BackToPrinceTrigger != (Object)null && (Object)(object)ProgressObject_Bel != (Object)null)
				{
					encounter = worldHandler?.GetValue<Encounter>("currentEncounter", Array.Empty<object>());
					GameObject gameObject = ((Component)this).gameObject;
					Encounter obj = encounter;
					gameObject.SetActive(((obj != null) ? ((Object)obj).name : null) == "CombatEncounter_IreneUnlockChallenge" || ShouldBeActive);
					((Component)ProgressObject_AmbushEnemies).gameObject.SetActive(ShouldBeActive);
				}
				else if (unlocked)
				{
					Core.OnAlwaysUpdate -= new OnUpdateHandler(CheckShouldBeActive);
					((Component)ProgressObject_AmbushEnemies).gameObject.SetActive(false);
				}
			}
		}

		public void OnDestroy()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			Core.OnAlwaysUpdate -= new OnUpdateHandler(CheckShouldBeActive);
		}
	}
}
namespace TrueBingo.BingoSyncManager
{
	internal class BingoSyncGUI : MonoBehaviour
	{
		public static bool GUIOpen = false;

		public static bool Countdown = false;

		public static bool Pause = false;

		public static string countdownMessage = "";

		private Dictionary<string, string> textFields = new Dictionary<string, string>();

		private const float windowY = 60f;

		private const float windowW = 500f;

		private const float windowH = 200f;

		private const float elementX = 20f;

		private const float elementH = 20f;

		private const float elementPadding = 4f;

		public const float labelSpace = 110f;

		private int index;

		private const string windowName = "BingoSync";

		public static string errorMessage = string.Empty;

		private readonly int possibleColors = Enum.GetValues(typeof(PlayerColors)).Length;

		private PlayerColors PlayerColor = (PlayerColors)1;

		private string RoomID = string.Empty;

		private string Password = string.Empty;

		private string PlayerName = string.Empty;

		private float windowX => (float)Screen.width * 0.5f - 250f;

		private float elementY => 20f + 20f * (float)(index - 1) + 4f * (float)index;

		public static float elementW => 460f;

		private Rect elementRect => new Rect(20f, elementY, elementW, 20f);

		private string ConnectionColor
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Invalid comparison between Unknown and I4
				if ((int)TrueBingoSync.bingoSync.Status != 0)
				{
					if ((int)TrueBingoSync.bingoSync.Status != 1)
					{
						return "red";
					}
					return "orange";
				}
				return "lime";
			}
		}

		private string ConnectColor
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Invalid comparison between Unknown and I4
				if ((int)TrueBingoSync.bingoSync.Status != 3)
				{
					return "grey";
				}
				return "white";
			}
		}

		private string DisconnectionColor
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				if ((int)TrueBingoSync.bingoSync.Status != 0)
				{
					return "grey";
				}
				return "red";
			}
		}

		private void Awake()
		{
			UpdateBingoSyncConfig("Room ID", ref RoomID);
			UpdateBingoSyncConfig("Room Password", ref Password);
			UpdateBingoSyncConfig("Player Name", ref PlayerName);
			UpdateBingoSyncConfig("Player Color", ref PlayerColor);
			if (BingoConfig.autoconnect && RoomID != string.Empty && PlayerName != string.Empty)
			{
				JoinRoom();
			}
		}

		private void UpdateBingoSyncConfig<T>(string key, ref T reference)
		{
			ConfigEntry<T> val = default(ConfigEntry<T>);
			if (BingoConfig.config_bingosync.TryGetEntry<T>("BingoSync", key, ref val))
			{
				reference = val.Value;
			}
		}

		private void SetBingoSyncConfigValue<T>(string key, T value)
		{
			ConfigEntry<T> val = default(ConfigEntry<T>);
			if (BingoConfig.config_bingosync.TryGetEntry<T>("BingoSync", key, ref val))
			{
				val.Value = value;
			}
		}

		private void OnGUI()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			BingoSyncGUIConfig.SetupStyles();
			if (GUIOpen)
			{
				GUIWindow(0, "BingoSync", new Color(0f, 0f, 0f, 1f));
			}
			if (Pause)
			{
				GUI.contentColor = Color.black;
				GUI.Label(new Rect(3f, 3f, (float)Screen.width, (float)Screen.height), "Paused", BingoSyncGUIConfig.Styles.Pause);
				GUI.contentColor = Color.red;
				GUI.Label(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), "Paused", BingoSyncGUIConfig.Styles.Pause);
			}
			if (Countdown)
			{
				Pause = false;
				GUIStyle countdownLabel = BingoSyncGUIConfig.GetCountdownLabel();
				GUI.contentColor = Color.black;
				GUI.Label(new Rect(3f, 3f, (float)Screen.width, (float)Screen.height), countdownMessage, countdownLabel);
				GUI.contentColor = Color.white;
				GUI.Label(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), countdownMessage, countdownLabel);
			}
		}

		private Color PlayerColorToColor(PlayerColors playerColor)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected I4, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			return (Color)((int)playerColor switch
			{
				0 => BingoSyncGUIConfig.Colors.Orange, 
				1 => BingoSyncGUIConfig.Colors.Red, 
				2 => BingoSyncGUIConfig.Colors.Blue, 
				3 => BingoSyncGUIConfig.Colors.Green, 
				4 => BingoSyncGUIConfig.Colors.Purple, 
				5 => BingoSyncGUIConfig.Colors.Navy, 
				6 => BingoSyncGUIConfig.Colors.Teal, 
				7 => BingoSyncGUIConfig.Colors.Brown, 
				8 => BingoSyncGUIConfig.Colors.Pink, 
				9 => BingoSyncGUIConfig.Colors.Yellow, 
				_ => Color.black, 
			});
		}

		private void HandleGUI(int windowID)
		{
			//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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Invalid comparison between Unknown and I4
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Invalid comparison between Unknown and I4
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			index = 0;
			if (GUIButton("Color: " + ((object)(PlayerColors)(ref PlayerColor)).ToString(), PlayerColorToColor(PlayerColor)) && !TrueBingoSync.IsUpdatingColor && (int)TrueBingoSync.bingoSync.Status != 1 && (int)TrueBingoSync.bingoSync.Status != 2)
			{
				PlayerColor = (PlayerColors)(((int)PlayerColor < possibleColors - 1) ? (PlayerColor + 1) : 0);
				TrueBingoSync.SetPlayerColor(PlayerColor);
				SetBingoSyncConfigValue<PlayerColors>("Player Color", PlayerColor);
				BingoConfig.config_bingosync.Save();
			}
			RoomID = GUITextField("RoomID", RoomID, Color.white, Color.white, "Room ID:", password: true);
			Password = GUITextField("Password", Password, Color.white, Color.white, "Password:", password: true);
			PlayerName = GUITextField("Name", PlayerName, Color.white, Color.white, "Player Name:");
			GUILabel(errorMessage, Color.red);
			string[] obj = new string[7] { "<color=", ConnectColor, ">Connect</color> <color=", ConnectionColor, ">(", null, null };
			ConnectionStatus status = TrueBingoSync.bingoSync.Status;
			obj[5] = ((object)(ConnectionStatus)(ref status)).ToString();
			obj[6] = ")</color>";
			if (GUIButton(string.Concat(obj), Color.gray) && (int)TrueBingoSync.bingoSync.Status == 3)
			{
				errorMessage = "";
				JoinRoom();
			}
			if (GUIButton("<color=" + DisconnectionColor + ">Disconnect</color>", Color.gray) && (int)TrueBingoSync.bingoSync.Status == 0)
			{
				TrueBingoSync.Disconnect();
			}
		}

		private Rect GUIWindow(int ID, string name, Color color)
		{
			//IL_0000: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			GUI.backgroundColor = color;
			index++;
			return GUI.Window(ID, new Rect(windowX, 60f, 500f, 200f), new WindowFunction(HandleGUI), "BingoSync");
		}

		private void GUILabel(string text, Color color, bool updateIndex = true, Rect customRect = default(Rect))
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (updateIndex)
			{
				index++;
			}
			GUI.contentColor = color;
			GUI.Label(updateIndex ? elementRect : customRect, text, BingoSyncGUIConfig.GetLabelStyle(!updateIndex));
		}

		private void JoinRoom()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			TrueBingoSync.JoinRoom(new RoomInfo(RoomID, Password, PlayerName, PlayerColor, false));
		}

		private bool GUIButton(string text, Color color)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			index++;
			Color val = default(Color);
			((Color)(ref val))..ctor(color.r / 255f, color.g / 255f, color.b / 255f, 0.7f);
			BingoSyncGUIConfig.Textures.Button_Background.SetPixel(0, 0, val);
			BingoSyncGUIConfig.Textures.Button_Background.Apply();
			BingoSyncGUIConfig.Textures.Button_Hover.SetPixel(0, 0, val * 1.1f);
			BingoSyncGUIConfig.Textures.Button_Hover.Apply();
			BingoSyncGUIConfig.Textures.Button_Click.SetPixel(0, 0, val * 0.8f);
			BingoSyncGUIConfig.Textures.Button_Click.Apply();
			return GUI.Button(elementRect, text, BingoSyncGUIConfig.Styles.Button);
		}

		private string GUITextField(string ID, string initialText, Color textColor, Color outlineColor, string label = null, bool password = false)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			index++;
			string value = initialText;
			if (!textFields.TryGetValue(ID, out value))
			{
				textFields.Add(ID, value);
			}
			if (value == null)
			{
				value = initialText;
			}
			GUI.contentColor = textColor;
			GUI.backgroundColor = outlineColor;
			Rect val = elementRect;
			if (label != null && label != string.Empty)
			{
				Rect val2 = elementRect;
				float num = ((Rect)(ref val2)).x + 110f;
				val2 = elementRect;
				float y = ((Rect)(ref val2)).y;
				val2 = elementRect;
				float num2 = ((Rect)(ref val2)).width - 110f;
				val2 = elementRect;
				((Rect)(ref val))..ctor(num, y, num2, ((Rect)(ref val2)).height);
				Color white = Color.white;
				val2 = elementRect;
				float x = ((Rect)(ref val2)).x;
				val2 = elementRect;
				float y2 = ((Rect)(ref val2)).y;
				val2 = elementRect;
				float num3 = ((Rect)(ref val2)).width - ((Rect)(ref val)).width;
				val2 = elementRect;
				GUILabel(label, white, updateIndex: false, new Rect(x, y2, num3, ((Rect)(ref val2)).height));
			}
			string empty = string.Empty;
			empty = ((!password) ? GUI.TextField(val, value) : GUI.PasswordField(val, value, "*"[0], 64));
			return textFields[ID] = empty;
		}

		private void Update()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(BingoConfig.menukey))
			{
				GUIOpen = !GUIOpen;
				Core instance = Core.Instance;
				GameInput val = ((instance != null) ? instance.GameInput : null);
				if (GUIOpen)
				{
					if (val != null)
					{
						val.DisableMouse(0);
					}
				}
				else
				{
					if (instance != null)
					{
						BaseModule baseModule = instance.BaseModule;
						if (baseModule != null)
						{
							baseModule.RestoreMouseInputState();
						}
					}
					if (val != null)
					{
						val.EnableMouse(0);
					}
				}
			}
			if (GUIOpen)
			{
				Cursor.visible = true;
			}
		}
	}
	internal static class BingoSyncGUIConfig
	{
		public static class Styles
		{
			public static GUIStyle Button;

			public static GUIStyle Label;

			public static GUIStyle LabelCountdown;

			public static GUIStyle Pause;
		}

		public static class Textures
		{
			public static readonly Texture2D Button_Background = new Texture2D(1, 1);

			public static readonly Texture2D Button_Hover = new Texture2D(1, 1);

			public static readonly Texture2D Button_Click = new Texture2D(1, 1);
		}

		public static class Colors
		{
			public static readonly Color Orange = new Color(254f, 154f, 20f);

			public static readonly Color Red = new Color(247f, 72f, 67f);

			public static readonly Color Blue = new Color(62f, 157f, 248f);

			public static readonly Color Green = new Color(39f, 209f, 16f);

			public static readonly Color Purple = new Color(128f, 44f, 189f);

			public static readonly Color Navy = new Color(11f, 66f, 168f);

			public static readonly Color Teal = new Color(62f, 145f, 144f);

			public static readonly Color Brown = new Color(162f, 87f, 33f);

			public static readonly Color Pink = new Color(232f, 131f, 166f);

			public static readonly Color Yellow = new Color(212f, 205f, 19f);
		}

		private static bool stylesSetUp;

		public static void SetupStyles()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			if (!stylesSetUp)
			{
				Styles.Button = new GUIStyle(GUI.skin.button);
				Styles.Button.normal.background = Textures.Button_Background;
				Styles.Button.hover.background = Textures.Button_Hover;
				Styles.Button.active.background = Textures.Button_Click;
				Styles.Label = new GUIStyle(GUI.skin.label);
				Styles.Label.alignment = (TextAnchor)4;
				Styles.Label.wordWrap = false;
				Styles.Label.fontStyle = (FontStyle)1;
				Styles.LabelCountdown = new GUIStyle(GUI.skin.label);
				Styles.LabelCountdown.fixedWidth = Screen.width;
				Styles.LabelCountdown.alignment = (TextAnchor)4;
				Styles.LabelCountdown.wordWrap = false;
				Styles.LabelCountdown.fontStyle = (FontStyle)1;
				Styles.Pause = new GUIStyle(GUI.skin.label);
				Styles.Pause.fixedWidth = Screen.width;
				Styles.Pause.alignment = (TextAnchor)4;
				Styles.Pause.wordWrap = false;
				Styles.Pause.fontStyle = (FontStyle)1;
				Styles.Pause.fontSize = Mathf.FloorToInt((float)Screen.width * 0.05f);
				stylesSetUp = true;
			}
		}

		public static GUIStyle GetLabelStyle(bool field = false)
		{
			Styles.Label.fixedWidth = (field ? 110f : BingoSyncGUI.elementW);
			return Styles.Label;
		}

		public static GUIStyle GetCountdownLabel()
		{
			int num = 1;
			if (int.TryParse(BingoSyncGUI.countdownMessage, out var result))
			{
				num = result;
			}
			int num2 = Mathf.FloorToInt((float)Screen.width * 0.08f);
			int num3 = num2 / 4;
			Styles.LabelCountdown.fontSize = num2 + (5 * num3 - Mathf.FloorToInt((float)(num * num3)));
			return Styles.LabelCountdown;
		}
	}
	internal static class TrueBingoSync
	{
		public enum ObjectiveType
		{
			ItemPickup,
			CharacterUnlock,
			TaxiDriver,
			Rep
		}

		public static readonly BingoSync bingoSync = new BingoSync();

		public static bool IsUpdatingColor = false;

		private static bool _paused = false;

		private static List<MessageReceived> receivers = new List<MessageReceived>();

		private static readonly Dictionary<Stage, string> StageToName = new Dictionary<Stage, string>
		{
			{
				(Stage)5,
				"Hideout"
			},
			{
				(Stage)12,
				"Brink"
			},
			{
				(Stage)6,
				"Mall"
			},
			{
				(Stage)7,
				"Mataan"
			},
			{
				(Stage)11,
				"Square"
			},
			{
				(Stage)4,
				"Versum"
			},
			{
				(Stage)9,
				"Pyramid"
			}
		};

		private static AppEmail EmailApp
		{
			get
			{
				WorldHandler instance = WorldHandler.instance;
				if (instance == null)
				{
					return null;
				}
				Player currentPlayer = instance.GetCurrentPlayer();
				if (currentPlayer == null)
				{
					return null;
				}
				Phone value = currentPlayer.GetValue<Phone>("phone", Array.Empty<object>());
				if (value == null)
				{
					return null;
				}
				return value.GetAppInstance<AppEmail>();
			}
		}

		private static void OnMessage(SocketMessage message)
		{
			if (message.type == "goal" && BingoConfig.phonenotification)
			{
				SendNotification(message);
			}
			else
			{
				if (!(message.type == "chat"))
				{
					return;
				}
				string text = message.text;
				if (text == null || text == string.Empty)
				{
					return;
				}
				text = text.Trim();
				if (!text.StartsWith("!"))
				{
					return;
				}
				text = text.Substring(1).Trim(new char[1] { ' ' });
				string[] array = new string[1] { text };
				if (Enumerable.Contains(array[0], ' '))
				{
					array = text.Split(new char[1] { ' ' });
				}
				switch (array[0].ToLower())
				{
				case "start":
					StartCountdown();
					break;
				case "ping":
					SendMessage("pong", networkReply: true);
					break;
				case "pause":
				{
					Core instance = Core.Instance;
					if (instance != null)
					{
						instance.PauseCore((PauseType)8);
					}
					_paused = true;
					BingoSyncGUI.Pause = true;
					break;
				}
				case "resume":
					StartCountdown(resume: true);
					break;
				case "help":
					if (message.player.name.ToLower().Trim() == bingoSync.CurrentRoomInfo.PlayerName.ToLower().Trim())
					{
						SendMessage("[!start] Start Countdown, [!pause] Pause all players, [!resume] Resume all players, [!ping] Test players connection");
					}
					break;
				}
			}
		}

		public static void Update()
		{
			if (_paused && !Core.Instance.IsCorePaused)
			{
				Core.Instance.PauseCore((PauseType)8);
			}
		}

		private static async void StartCountdown(bool resume = false)
		{
			if (_paused && !resume)
			{
				return;
			}
			if (resume)
			{
				while (BingoSyncGUI.Countdown)
				{
					await Task.Yield();
				}
			}
			if (BingoSyncGUI.Countdown)
			{
				return;
			}
			BingoSyncGUI.countdownMessage = "";
			BingoSyncGUI.Countdown = true;
			BingoSyncGUI.Pause = false;
			int num = 5;
			Core instance = Core.Instance;
			AudioManager audioManager = ((instance != null) ? instance.AudioManager : null);
			MethodInfo PlaySfxGameplay = null;
			if (audioManager != null)
			{
				PlaySfxGameplay = ((object)audioManager).GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault((MethodInfo x) => x.Name == "PlaySfxGameplay" && x.GetParameters().Length == 3 && x.GetParameters().All((ParameterInfo y) => y.ParameterType == typeof(SfxCollectionID) || y.ParameterType == typeof(AudioClipID) || y.ParameterType == typeof(float)));
			}
			for (int i = num; i >= 0; i--)
			{
				if (i != 0)
				{
					PlaySfxGameplay?.Invoke(audioManager, new object[3]
					{
						(object)(SfxCollectionID)18,
						(object)(AudioClipID)985,
						0f
					});
					BingoSyncGUI.countdownMessage = i.ToString();
				}
				else
				{
					PlaySfxGameplay?.Invoke(audioManager, new object[3]
					{
						(object)(SfxCollectionID)19,
						(object)(AudioClipID)409,
						0f
					});
					BingoSyncGUI.countdownMessage = "GO!";
					if (resume)
					{
						_paused = false;
						Core instance2 = Core.Instance;
						if (instance2 != null)
						{
							instance2.UnPauseCore((PauseType)8);
						}
					}
				}
				await Task.Delay(TimeSpan.FromSeconds(1.0));
			}
			BingoSyncGUI.Countdown = false;
		}

		public static async void JoinRoom(RoomInfo roomInfo)
		{
			if ((int)(await bingoSync.JoinRoom(roomInfo)) == 0)
			{
				RemoveReceivers();
				AddReceiver(new MessageReceived(OnMessage));
			}
			else
			{
				BingoSyncGUI.errorMessage = "Failed Connection: Check Room ID / Password";
			}
		}

		public static async void Disconnect()
		{
			if ((int)bingoSync.Status == 0)
			{
				await bingoSync.Disconnect();
				RemoveReceivers();
			}
		}

		private static void RemoveReceivers()
		{
			for (int i = 0; i < receivers.Count; i++)
			{
				MessageReceived val = receivers[i];
				bingoSync.OnMessageReceived -= val;
			}
		}

		private static void AddReceiver(MessageReceived messageReceiver)
		{
			bingoSync.OnMessageReceived += messageReceiver;
			receivers.Add(messageReceiver);
		}

		public static async void SendMessage(string message, bool networkReply = false)
		{
			if ((int)bingoSync.Status == 0)
			{
				if (networkReply)
				{
					float networkTime = Time.time;
					await bingoSync.SendChatMessage("pong");
					message = $"{Time.time - networkTime}";
				}
				await bingoSync.SendChatMessage(message);
			}
		}

		public static async void MarkObjective(string itemToSend, ObjectiveType objectiveType, PickUpType? pickupType = null)
		{
			if ((int)bingoSync.Status != 0 || itemToSend == string.Empty)
			{
				return;
			}
			SlotInfo itemSlot = null;
			SlotInfo[] array = await bingoSync.GetBoardSlots();
			if (array == null || array.Length == 0)
			{
				return;
			}
			string stage = string.Empty;
			if (!StageToName.TryGetValue(Utility.GetCurrentStage(), out stage))
			{
				return;
			}
			switch (objectiveType)
			{
			case ObjectiveType.ItemPickup:
				if ((int)pickupType.GetValueOrDefault() != 5)
				{
					SlotInfo[] source = array.Where((SlotInfo x) => x.Info.ToLower().StartsWith(stage.ToLower()) && !Enumerable.Contains(x.Info, ':') && x.Info.Contains(" - ")).ToArray();
					itemSlot = ((IEnumerable<SlotInfo>)source).FirstOrDefault((Func<SlotInfo, bool>)((SlotInfo x) => x.Info != null && CompareItems(itemToSend, GetItemFromSlotName(x.Info))));
				}
				else
				{
					itemSlot = ((IEnumerable<SlotInfo>)array).FirstOrDefault((Func<SlotInfo, bool>)((SlotInfo x) => x.Info != null && Enumerable.Contains(x.Info, ':') && GetItemFromSlotName(x.Info).ToLower().Contains(itemToSend.ToLower())));
				}
				break;
			case ObjectiveType.CharacterUnlock:
				itemToSend = itemToSend.ToLower().Trim();
				if (Enumerable.Contains(itemToSend, ' '))
				{
					itemToSend = itemToSend.Split(new char[1] { ' ' })[0];
				}
				itemSlot = ((IEnumerable<SlotInfo>)array).FirstOrDefault((Func<SlotInfo, bool>)((SlotInfo x) => x.Info.ToLower().Contains("(" + stage.ToLower() + ")") && x.Info.ToLower().Contains("unlock " + itemToSend)));
				break;
			case ObjectiveType.TaxiDriver:
				itemSlot = ((IEnumerable<SlotInfo>)array).FirstOrDefault((Func<SlotInfo, bool>)((SlotInfo x) => x.Info.ToLower().Contains("(" + stage.ToLower() + ")") && x.Info.ToLower().Contains(itemToSend.ToLower().Trim())));
				break;
			case ObjectiveType.Rep:
				itemToSend = itemToSend.ToLower().Trim();
				if (Enumerable.Contains(itemToSend, ' '))
				{
					itemToSend = itemToSend.Split(new char[1] { ' ' })[1];
				}
				itemSlot = ((IEnumerable<SlotInfo>)array).FirstOrDefault((Func<SlotInfo, bool>)((SlotInfo x) => x.Info.ToLower().Contains(" rep ") && x.Info.ToLower().Contains(itemToSend)));
				break;
			}
			if (itemSlot != null)
			{
				await bingoSync.SelectSlot(itemSlot.ID, true, (PlayerColors?)null);
			}
		}

		public static async void SetPlayerColor(PlayerColors playerColor)
		{
			//IL_000e: 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)
			IsUpdatingColor = true;
			await bingoSync.SetPlayerColor(playerColor);
			IsUpdatingColor = false;
		}

		private static string GetItemFromSlotName(string name)
		{
			Match match = Regex.Match(name, "- (.+?) -");
			if (!match.Success)
			{
				return string.Empty;
			}
			return match.Groups[1].Value;
		}

		private static bool CompareItems(string pickup, string itemOnBoard)
		{
			pickup = pickup.ToLower();
			itemOnBoard = itemOnBoard.ToLower();
			if (pickup.Replace(" ", string.Empty).Trim().Equals(itemOnBoard.Replace(" ", string.Empty).Trim()))
			{
				return true;
			}
			int num = 0;
			int num2 = 2;
			int num3 = 3;
			for (int i = 0; i < itemOnBoard.Length; i++)
			{
				if (i + (num2 - 1) <= itemOnBoard.Length - 1)
				{
					string value = itemOnBoard.Substring(i, num2);
					if (pickup.Contains(value))
					{
						num += num3;
					}
				}
				else
				{
					num--;
				}
			}
			int num4 = Mathf.Abs(pickup.Length - itemOnBoard.Length);
			num -= num4;
			int num5 = Mathf.FloorToInt((float)itemOnBoard.Length * ((float)num3 * 0.5f) - (float)num4);
			return num >= num5;
		}

		public static void SendNotification(SocketMessage response)
		{
			SocketSlot square = response.square;
			string obj = ((square != null) ? square.colors : null);
			SocketPlayer player = response.player;
			string text = ((player != null) ? player.name : null);
			SocketSlot square2 = response.square;
			string collection = ((square2 != null) ? square2.name : null);
			if (obj == null || text == null || collection == null || response.remove)
			{
				return;
			}
			string text2 = collection;
			string text3 = StageToName.Values.ToArray().FirstOrDefault((string x) => collection.Trim().StartsWith(x) || collection.Trim().EndsWith("(" + x + ")") || (collection.ToLower().Contains(" rep ") && collection.Contains(x)));
			if (collection.Contains(" - "))
			{
				text2 = GetItemFromSlotName(collection);
			}
			else if (Regex.Match(collection, "\\((.+?)\\)").Success)
			{
				text2 = collection.Substring(0, collection.IndexOf('(') - 1).Trim();
			}
			else if (collection.ToLower().Contains(" rep "))
			{
				text2 = collection.Substring(collection.ToLower().IndexOf("rep "));
			}
			if (text != string.Empty && text2 != string.Empty && text.ToLower().Replace(" ", "").Trim() != bingoSync.CurrentRoomInfo.PlayerName.ToLower().Replace(" ", "").Trim())
			{
				string text4 = text + ": \"" + text2 + "\"";
				if (text3 != null && text3 != string.Empty)
				{
					text4 = text4 + " (" + text3 + ")";
				}
				WaitThenSendNotification(text4);
			}
		}

		private static async void WaitThenSendNotification(string notification)
		{
			Core instance = Core.Instance;
			BaseModule val = ((instance != null) ? instance.BaseModule : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (val.IsLoading)
			{
				AppEmail val2 = await GetEmailApp(Time.time + (float)TimeSpan.FromSeconds(10.0).TotalSeconds);
				if ((Object)(object)val2 != (Object)null)
				{
					((App)val2).PushNotification(notification, (AUnlockable)null);
				}
			}
			else
			{
				AppEmail emailApp = EmailApp;
				if (emailApp != null)
				{
					((App)emailApp).PushNotification(notification, (AUnlockable)null);
				}
			}
		}

		private static async Task<AppEmail> GetEmailApp(float endAfter)
		{
			AppEmail appEmail = null;
			while ((Object)(object)appEmail == (Object)null && !(Time.time > endAfter))
			{
				appEmail = EmailApp;
				if ((Object)(object)appEmail == (Object)null)
				{
					await Task.Yield();
				}
			}
			return appEmail;
		}
	}
}