Decompiled source of Archipelago v3.5.0

Archipelago.MultiClient.Net.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Archipelago.MultiClient.Net.Colors;
using Archipelago.MultiClient.Net.ConcurrentCollection;
using Archipelago.MultiClient.Net.Converters;
using Archipelago.MultiClient.Net.DataPackage;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Exceptions;
using Archipelago.MultiClient.Net.Extensions;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.MessageLog.Messages;
using Archipelago.MultiClient.Net.MessageLog.Parts;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: Guid("35a803ad-85ed-42e9-b1e3-c6b72096f0c1")]
[assembly: InternalsVisibleTo("Archipelago.MultiClient.Net.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
[assembly: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")]
[assembly: AssemblyFileVersion("6.7.1.0")]
[assembly: AssemblyInformationalVersion("6.7.1+0c57591db30f2497b0b4fef87164aa2bbe2e51b2")]
[assembly: AssemblyProduct("Archipelago.MultiClient.Net")]
[assembly: AssemblyTitle("Archipelago.MultiClient.Net")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")]
[assembly: AssemblyVersion("6.7.1.0")]
internal interface IConcurrentHashSet<T>
{
	bool TryAdd(T item);

	bool Contains(T item);

	void UnionWith(T[] otherSet);

	T[] ToArray();

	ReadOnlyCollection<T> AsToReadOnlyCollection();

	ReadOnlyCollection<T> AsToReadOnlyCollectionExcept(IConcurrentHashSet<T> otherSet);
}
public class AttemptingStringEnumConverter : StringEnumConverter
{
	public AttemptingStringEnumConverter()
	{
	}

	public AttemptingStringEnumConverter(Type namingStrategyType)
		: base(namingStrategyType)
	{
	}

	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
	{
		try
		{
			return ((StringEnumConverter)this).ReadJson(reader, objectType, existingValue, serializer);
		}
		catch (JsonSerializationException)
		{
			return objectType.IsValueType ? Activator.CreateInstance(objectType) : null;
		}
	}
}
namespace Archipelago.MultiClient.Net
{
	[Serializable]
	public abstract class ArchipelagoPacketBase
	{
		[JsonIgnore]
		internal JObject jobject;

		[JsonProperty("cmd")]
		[JsonConverter(typeof(StringEnumConverter))]
		public abstract ArchipelagoPacketType PacketType { get; }

		public JObject ToJObject()
		{
			return jobject;
		}
	}
	public interface IArchipelagoSession : IArchipelagoSessionActions
	{
		IArchipelagoSocketHelper Socket { get; }

		IReceivedItemsHelper Items { get; }

		ILocationCheckHelper Locations { get; }

		IPlayerHelper Players { get; }

		IDataStorageHelper DataStorage { get; }

		IConnectionInfoProvider ConnectionInfo { get; }

		IRoomStateHelper RoomState { get; }

		IMessageLogHelper MessageLog { get; }

		IHintsHelper Hints { get; }

		Task<RoomInfoPacket> ConnectAsync();

		Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true);

		LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true);
	}
	public class ArchipelagoSession : IArchipelagoSession, IArchipelagoSessionActions
	{
		private const int ArchipelagoConnectionTimeoutInSeconds = 4;

		private ConnectionInfoHelper connectionInfo;

		private TaskCompletionSource<LoginResult> loginResultTask = new TaskCompletionSource<LoginResult>();

		private TaskCompletionSource<RoomInfoPacket> roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>();

		public IArchipelagoSocketHelper Socket { get; }

		public IReceivedItemsHelper Items { get; }

		public ILocationCheckHelper Locations { get; }

		public IPlayerHelper Players { get; }

		public IDataStorageHelper DataStorage { get; }

		public IConnectionInfoProvider ConnectionInfo => connectionInfo;

		public IRoomStateHelper RoomState { get; }

		public IMessageLogHelper MessageLog { get; }

		public IHintsHelper Hints { get; }

		internal ArchipelagoSession(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IRoomStateHelper roomState, ConnectionInfoHelper connectionInfoHelper, IDataStorageHelper dataStorage, IMessageLogHelper messageLog, IHintsHelper createHints)
		{
			Socket = socket;
			Items = items;
			Locations = locations;
			Players = players;
			RoomState = roomState;
			connectionInfo = connectionInfoHelper;
			DataStorage = dataStorage;
			MessageLog = messageLog;
			Hints = createHints;
			socket.PacketReceived += Socket_PacketReceived;
		}

		private void Socket_PacketReceived(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket) && !(packet is ConnectionRefusedPacket))
			{
				if (packet is RoomInfoPacket result)
				{
					roomInfoPacketTask.TrySetResult(result);
				}
			}
			else
			{
				loginResultTask.TrySetResult(LoginResult.FromPacket(packet));
			}
		}

		public Task<RoomInfoPacket> ConnectAsync()
		{
			roomInfoPacketTask = new TaskCompletionSource<RoomInfoPacket>();
			Task.Factory.StartNew(delegate
			{
				try
				{
					Task task = Socket.ConnectAsync();
					task.Wait(TimeSpan.FromSeconds(4.0));
					if (!task.IsCompleted)
					{
						roomInfoPacketTask.TrySetCanceled();
					}
				}
				catch (AggregateException)
				{
					roomInfoPacketTask.TrySetCanceled();
				}
			});
			return roomInfoPacketTask.Task;
		}

		public Task<LoginResult> LoginAsync(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true)
		{
			loginResultTask = new TaskCompletionSource<LoginResult>();
			if (!roomInfoPacketTask.Task.IsCompleted)
			{
				loginResultTask.TrySetResult(new LoginFailure("You are not connected, run ConnectAsync() first"));
				return loginResultTask.Task;
			}
			connectionInfo.SetConnectionParameters(game, tags, itemsHandlingFlags, uuid);
			try
			{
				Socket.SendPacket(BuildConnectPacket(name, password, version, requestSlotData));
			}
			catch (ArchipelagoSocketClosedException)
			{
				loginResultTask.TrySetResult(new LoginFailure("You are not connected, run ConnectAsync() first"));
				return loginResultTask.Task;
			}
			SetResultAfterTimeout(loginResultTask, 4, new LoginFailure("Connection timed out."));
			return loginResultTask.Task;
		}

		private static void SetResultAfterTimeout<T>(TaskCompletionSource<T> task, int timeoutInSeconds, T result)
		{
			new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)).Token.Register(delegate
			{
				task.TrySetResult(result);
			});
		}

		public LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true)
		{
			Task<RoomInfoPacket> task = ConnectAsync();
			try
			{
				task.Wait(TimeSpan.FromSeconds(4.0));
			}
			catch (AggregateException ex)
			{
				if (ex.GetBaseException() is OperationCanceledException)
				{
					return new LoginFailure("Connection timed out.");
				}
				return new LoginFailure(ex.GetBaseException().Message);
			}
			if (!task.IsCompleted)
			{
				return new LoginFailure("Connection timed out.");
			}
			return LoginAsync(game, name, itemsHandlingFlags, version, tags, uuid, password, requestSlotData).Result;
		}

		private ConnectPacket BuildConnectPacket(string name, string password, Version version, bool requestSlotData)
		{
			return new ConnectPacket
			{
				Game = ConnectionInfo.Game,
				Name = name,
				Password = password,
				Tags = ConnectionInfo.Tags,
				Uuid = ConnectionInfo.Uuid,
				Version = ((version != null) ? new NetworkVersion(version) : new NetworkVersion(0, 6, 0)),
				ItemsHandling = ConnectionInfo.ItemsHandlingFlags,
				RequestSlotData = requestSlotData
			};
		}

		public void Say(string message)
		{
			Socket.SendPacket(new SayPacket
			{
				Text = message
			});
		}

		public void SetClientState(ArchipelagoClientState state)
		{
			Socket.SendPacket(new StatusUpdatePacket
			{
				Status = state
			});
		}

		public void SetGoalAchieved()
		{
			SetClientState(ArchipelagoClientState.ClientGoal);
		}
	}
	public interface IArchipelagoSessionActions
	{
		void Say(string message);

		void SetClientState(ArchipelagoClientState state);

		void SetGoalAchieved();
	}
	public static class ArchipelagoSessionFactory
	{
		public static ArchipelagoSession CreateSession(Uri uri)
		{
			ArchipelagoSocketHelper socket = new ArchipelagoSocketHelper(uri);
			DataPackageCache cache = new DataPackageCache(socket);
			ConnectionInfoHelper connectionInfoHelper = new ConnectionInfoHelper(socket);
			PlayerHelper playerHelper = new PlayerHelper(socket, connectionInfoHelper);
			ItemInfoResolver itemInfoResolver = new ItemInfoResolver(cache, connectionInfoHelper);
			LocationCheckHelper locationCheckHelper = new LocationCheckHelper(socket, itemInfoResolver, connectionInfoHelper, playerHelper);
			ReceivedItemsHelper items = new ReceivedItemsHelper(socket, locationCheckHelper, itemInfoResolver, connectionInfoHelper, playerHelper);
			RoomStateHelper roomStateHelper = new RoomStateHelper(socket, locationCheckHelper);
			DataStorageHelper dataStorageHelper = new DataStorageHelper(socket, connectionInfoHelper);
			MessageLogHelper messageLog = new MessageLogHelper(socket, itemInfoResolver, playerHelper, connectionInfoHelper);
			HintsHelper createHints = new HintsHelper(socket, playerHelper, locationCheckHelper, roomStateHelper, dataStorageHelper);
			return new ArchipelagoSession(socket, items, locationCheckHelper, playerHelper, roomStateHelper, connectionInfoHelper, dataStorageHelper, messageLog, createHints);
		}

		public static ArchipelagoSession CreateSession(string hostname, int port = 38281)
		{
			return CreateSession(ParseUri(hostname, port));
		}

		internal static Uri ParseUri(string hostname, int port)
		{
			string text = hostname;
			if (!text.StartsWith("ws://") && !text.StartsWith("wss://"))
			{
				text = "unspecified://" + text;
			}
			if (!text.Substring(text.IndexOf("://", StringComparison.Ordinal) + 3).Contains(":"))
			{
				text += $":{port}";
			}
			if (text.EndsWith(":"))
			{
				text += port;
			}
			return new Uri(text);
		}
	}
	public abstract class LoginResult
	{
		public abstract bool Successful { get; }

		public static LoginResult FromPacket(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket connectedPacket))
			{
				if (packet is ConnectionRefusedPacket connectionRefusedPacket)
				{
					return new LoginFailure(connectionRefusedPacket);
				}
				throw new ArgumentOutOfRangeException("packet", "packet is not a connection result packet");
			}
			return new LoginSuccessful(connectedPacket);
		}
	}
	public class LoginSuccessful : LoginResult
	{
		public override bool Successful => true;

		public int Team { get; }

		public int Slot { get; }

		public Dictionary<string, object> SlotData { get; }

		public LoginSuccessful(ConnectedPacket connectedPacket)
		{
			Team = connectedPacket.Team;
			Slot = connectedPacket.Slot;
			SlotData = connectedPacket.SlotData;
		}
	}
	public class LoginFailure : LoginResult
	{
		public override bool Successful => false;

		public ConnectionRefusedError[] ErrorCodes { get; }

		public string[] Errors { get; }

		public LoginFailure(ConnectionRefusedPacket connectionRefusedPacket)
		{
			if (connectionRefusedPacket.Errors != null)
			{
				ErrorCodes = connectionRefusedPacket.Errors.ToArray();
				Errors = ErrorCodes.Select(GetErrorMessage).ToArray();
			}
			else
			{
				ErrorCodes = new ConnectionRefusedError[0];
				Errors = new string[0];
			}
		}

		public LoginFailure(string message)
		{
			ErrorCodes = new ConnectionRefusedError[0];
			Errors = new string[1] { message };
		}

		private static string GetErrorMessage(ConnectionRefusedError errorCode)
		{
			return errorCode switch
			{
				ConnectionRefusedError.InvalidSlot => "The slot name did not match any slot on the server.", 
				ConnectionRefusedError.InvalidGame => "The slot is set to a different game on the server.", 
				ConnectionRefusedError.SlotAlreadyTaken => "The slot already has a connection with a different uuid established.", 
				ConnectionRefusedError.IncompatibleVersion => "The client and server version mismatch.", 
				ConnectionRefusedError.InvalidPassword => "The password is invalid.", 
				ConnectionRefusedError.InvalidItemsHandling => "The item handling flags provided are invalid.", 
				_ => $"Unknown error: {errorCode}.", 
			};
		}
	}
	internal class TwoWayLookup<TA, TB> : IEnumerable<KeyValuePair<TB, TA>>, IEnumerable
	{
		private readonly Dictionary<TA, TB> aToB = new Dictionary<TA, TB>();

		private readonly Dictionary<TB, TA> bToA = new Dictionary<TB, TA>();

		public TA this[TB b] => bToA[b];

		public TB this[TA a] => aToB[a];

		public void Add(TA a, TB b)
		{
			aToB[a] = b;
			bToA[b] = a;
		}

		public void Add(TB b, TA a)
		{
			Add(a, b);
		}

		public bool TryGetValue(TA a, out TB b)
		{
			return aToB.TryGetValue(a, out b);
		}

		public bool TryGetValue(TB b, out TA a)
		{
			return bToA.TryGetValue(b, out a);
		}

		public IEnumerator<KeyValuePair<TB, TA>> GetEnumerator()
		{
			return bToA.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}
	}
}
namespace Archipelago.MultiClient.Net.Packets
{
	public class BouncedPacket : BouncePacket
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounced;
	}
	public class BouncePacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Bounce;

		[JsonProperty("games")]
		public List<string> Games { get; set; } = new List<string>();


		[JsonProperty("slots")]
		public List<int> Slots { get; set; } = new List<int>();


		[JsonProperty("tags")]
		public List<string> Tags { get; set; } = new List<string>();


		[JsonProperty("data")]
		public Dictionary<string, JToken> Data { get; set; }
	}
	public class ConnectedPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connected;

		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }

		[JsonProperty("players")]
		public NetworkPlayer[] Players { get; set; }

		[JsonProperty("missing_locations")]
		public long[] MissingChecks { get; set; }

		[JsonProperty("checked_locations")]
		public long[] LocationsChecked { get; set; }

		[JsonProperty("slot_data")]
		public Dictionary<string, object> SlotData { get; set; }

		[JsonProperty("slot_info")]
		public Dictionary<int, NetworkSlot> SlotInfo { get; set; }

		[JsonProperty("hint_points")]
		public int? HintPoints { get; set; }
	}
	public class ConnectionRefusedPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectionRefused;

		[JsonProperty("errors", ItemConverterType = typeof(AttemptingStringEnumConverter))]
		public ConnectionRefusedError[] Errors { get; set; }
	}
	public class ConnectPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Connect;

		[JsonProperty("password")]
		public string Password { get; set; }

		[JsonProperty("game")]
		public string Game { get; set; }

		[JsonProperty("name")]
		public string Name { get; set; }

		[JsonProperty("uuid")]
		public string Uuid { get; set; }

		[JsonProperty("version")]
		public NetworkVersion Version { get; set; }

		[JsonProperty("tags")]
		public string[] Tags { get; set; }

		[JsonProperty("items_handling")]
		public ItemsHandlingFlags ItemsHandling { get; set; }

		[JsonProperty("slot_data")]
		public bool RequestSlotData { get; set; }
	}
	public class ConnectUpdatePacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ConnectUpdate;

		[JsonProperty("tags")]
		public string[] Tags { get; set; }

		[JsonProperty("items_handling")]
		public ItemsHandlingFlags? ItemsHandling { get; set; }
	}
	public class CreateHintsPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.CreateHints;

		[JsonProperty("locations")]
		public long[] Locations { get; set; }

		[JsonProperty("player")]
		public int Player { get; set; }

		[JsonProperty("status")]
		public HintStatus Status { get; set; }
	}
	public class DataPackagePacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.DataPackage;

		[JsonProperty("data")]
		public Archipelago.MultiClient.Net.Models.DataPackage DataPackage { get; set; }
	}
	public class GetDataPackagePacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.GetDataPackage;

		[JsonProperty("games")]
		public string[] Games { get; set; }
	}
	public class GetPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Get;

		[JsonProperty("keys")]
		public string[] Keys { get; set; }
	}
	public class InvalidPacketPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.InvalidPacket;

		[JsonProperty("type")]
		public InvalidPacketErrorType ErrorType { get; set; }

		[JsonProperty("text")]
		public string ErrorText { get; set; }

		[JsonProperty("original_cmd")]
		public ArchipelagoPacketType OriginalCmd { get; set; }
	}
	public class LocationChecksPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationChecks;

		[JsonProperty("locations")]
		public long[] Locations { get; set; }
	}
	public class LocationInfoPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationInfo;

		[JsonProperty("locations")]
		public NetworkItem[] Locations { get; set; }
	}
	public class LocationScoutsPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.LocationScouts;

		[JsonProperty("locations")]
		public long[] Locations { get; set; }

		[JsonProperty("create_as_hint")]
		public int CreateAsHint { get; set; }
	}
	public class PrintJsonPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.PrintJSON;

		[JsonProperty("data")]
		public JsonMessagePart[] Data { get; set; }

		[JsonProperty("type")]
		[JsonConverter(typeof(AttemptingStringEnumConverter))]
		public JsonMessageType? MessageType { get; set; }
	}
	public class ItemPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("receiving")]
		public int ReceivingPlayer { get; set; }

		[JsonProperty("item")]
		public NetworkItem Item { get; set; }
	}
	public class ItemCheatPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("receiving")]
		public int ReceivingPlayer { get; set; }

		[JsonProperty("item")]
		public NetworkItem Item { get; set; }

		[JsonProperty("team")]
		public int Team { get; set; }
	}
	public class HintPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("receiving")]
		public int ReceivingPlayer { get; set; }

		[JsonProperty("item")]
		public NetworkItem Item { get; set; }

		[JsonProperty("found")]
		public bool? Found { get; set; }
	}
	public class JoinPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }

		[JsonProperty("tags")]
		public string[] Tags { get; set; }
	}
	public class LeavePrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }
	}
	public class ChatPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }

		[JsonProperty("message")]
		public string Message { get; set; }
	}
	public class ServerChatPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("message")]
		public string Message { get; set; }
	}
	public class TutorialPrintJsonPacket : PrintJsonPacket
	{
	}
	public class TagsChangedPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }

		[JsonProperty("tags")]
		public string[] Tags { get; set; }
	}
	public class CommandResultPrintJsonPacket : PrintJsonPacket
	{
	}
	public class AdminCommandResultPrintJsonPacket : PrintJsonPacket
	{
	}
	public class GoalPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }
	}
	public class ReleasePrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }
	}
	public class CollectPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }
	}
	public class CountdownPrintJsonPacket : PrintJsonPacket
	{
		[JsonProperty("countdown")]
		public int RemainingSeconds { get; set; }
	}
	public class ReceivedItemsPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.ReceivedItems;

		[JsonProperty("index")]
		public int Index { get; set; }

		[JsonProperty("items")]
		public NetworkItem[] Items { get; set; }
	}
	public class RetrievedPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Retrieved;

		[JsonProperty("keys")]
		public Dictionary<string, JToken> Data { get; set; }
	}
	public class RoomInfoPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomInfo;

		[JsonProperty("version")]
		public NetworkVersion Version { get; set; }

		[JsonProperty("generator_version")]
		public NetworkVersion GeneratorVersion { get; set; }

		[JsonProperty("tags")]
		public string[] Tags { get; set; }

		[JsonProperty("password")]
		public bool Password { get; set; }

		[JsonProperty("permissions")]
		public Dictionary<string, Permissions> Permissions { get; set; }

		[JsonProperty("hint_cost")]
		public int HintCostPercentage { get; set; }

		[JsonProperty("location_check_points")]
		public int LocationCheckPoints { get; set; }

		[JsonProperty("players")]
		public NetworkPlayer[] Players { get; set; }

		[JsonProperty("games")]
		public string[] Games { get; set; }

		[JsonProperty("datapackage_checksums")]
		public Dictionary<string, string> DataPackageChecksums { get; set; }

		[JsonProperty("seed_name")]
		public string SeedName { get; set; }

		[JsonProperty("time")]
		public double Timestamp { get; set; }
	}
	public class RoomUpdatePacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.RoomUpdate;

		[JsonProperty("tags")]
		public string[] Tags { get; set; }

		[JsonProperty("password")]
		public bool? Password { get; set; }

		[JsonProperty("permissions")]
		public Dictionary<string, Permissions> Permissions { get; set; } = new Dictionary<string, Permissions>();


		[JsonProperty("hint_cost")]
		public int? HintCostPercentage { get; set; }

		[JsonProperty("location_check_points")]
		public int? LocationCheckPoints { get; set; }

		[JsonProperty("players")]
		public NetworkPlayer[] Players { get; set; }

		[JsonProperty("hint_points")]
		public int? HintPoints { get; set; }

		[JsonProperty("checked_locations")]
		public long[] CheckedLocations { get; set; }
	}
	public class SayPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Say;

		[JsonProperty("text")]
		public string Text { get; set; }
	}
	public class SetNotifyPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetNotify;

		[JsonProperty("keys")]
		public string[] Keys { get; set; }
	}
	public class SetPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Set;

		[JsonProperty("key")]
		public string Key { get; set; }

		[JsonProperty("default")]
		public JToken DefaultValue { get; set; }

		[JsonProperty("operations")]
		public OperationSpecification[] Operations { get; set; }

		[JsonProperty("want_reply")]
		public bool WantReply { get; set; }

		[JsonExtensionData]
		public Dictionary<string, JToken> AdditionalArguments { get; set; }

		[OnDeserialized]
		internal void OnDeserializedMethod(StreamingContext context)
		{
			AdditionalArguments?.Remove("cmd");
		}
	}
	public class SetReplyPacket : SetPacket
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetReply;

		[JsonProperty("value")]
		public JToken Value { get; set; }

		[JsonProperty("original_value")]
		public JToken OriginalValue { get; set; }
	}
	public class StatusUpdatePacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.StatusUpdate;

		[JsonProperty("status")]
		public ArchipelagoClientState Status { get; set; }
	}
	public class SyncPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Sync;
	}
	internal class UnknownPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.Unknown;
	}
	public class UpdateHintPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.UpdateHint;

		[JsonProperty("player")]
		public int Player { get; set; }

		[JsonProperty("location")]
		public long Location { get; set; }

		[JsonProperty("status")]
		public HintStatus Status { get; set; }
	}
}
namespace Archipelago.MultiClient.Net.Models
{
	public struct Color : IEquatable<Color>
	{
		public static Color Red = new Color(byte.MaxValue, 0, 0);

		public static Color Green = new Color(0, 128, 0);

		public static Color Yellow = new Color(byte.MaxValue, byte.MaxValue, 0);

		public static Color Blue = new Color(0, 0, byte.MaxValue);

		public static Color Magenta = new Color(byte.MaxValue, 0, byte.MaxValue);

		public static Color Cyan = new Color(0, byte.MaxValue, byte.MaxValue);

		public static Color Black = new Color(0, 0, 0);

		public static Color White = new Color(byte.MaxValue, byte.MaxValue, byte.MaxValue);

		public static Color SlateBlue = new Color(106, 90, 205);

		public static Color Salmon = new Color(250, 128, 114);

		public static Color Plum = new Color(221, 160, 221);

		public byte R { get; set; }

		public byte G { get; set; }

		public byte B { get; set; }

		public Color(byte r, byte g, byte b)
		{
			R = r;
			G = g;
			B = b;
		}

		public override bool Equals(object obj)
		{
			if (obj is Color color && R == color.R && G == color.G)
			{
				return B == color.B;
			}
			return false;
		}

		public bool Equals(Color other)
		{
			if (R == other.R && G == other.G)
			{
				return B == other.B;
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((-1520100960 * -1521134295 + R.GetHashCode()) * -1521134295 + G.GetHashCode()) * -1521134295 + B.GetHashCode();
		}

		public static bool operator ==(Color left, Color right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(Color left, Color right)
		{
			return !(left == right);
		}
	}
	public class DataPackage
	{
		[JsonProperty("games")]
		public Dictionary<string, GameData> Games { get; set; } = new Dictionary<string, GameData>();

	}
	public class DataStorageElement
	{
		internal DataStorageElementContext Context;

		internal List<OperationSpecification> Operations = new List<OperationSpecification>(0);

		internal DataStorageHelper.DataStorageUpdatedHandler Callbacks;

		internal Dictionary<string, JToken> AdditionalArguments = new Dictionary<string, JToken>(0);

		private JToken cachedValue;

		public event DataStorageHelper.DataStorageUpdatedHandler OnValueChanged
		{
			add
			{
				Context.AddHandler(Context.Key, value);
			}
			remove
			{
				Context.RemoveHandler(Context.Key, value);
			}
		}

		internal DataStorageElement(DataStorageElementContext context)
		{
			Context = context;
		}

		internal DataStorageElement(OperationType operationType, JToken value)
		{
			Operations = new List<OperationSpecification>(1)
			{
				new OperationSpecification
				{
					OperationType = operationType,
					Value = value
				}
			};
		}

		internal DataStorageElement(DataStorageElement source, OperationType operationType, JToken value)
			: this(source.Context)
		{
			Operations = source.Operations.ToList();
			Callbacks = source.Callbacks;
			AdditionalArguments = source.AdditionalArguments;
			Operations.Add(new OperationSpecification
			{
				OperationType = operationType,
				Value = value
			});
		}

		internal DataStorageElement(DataStorageElement source, Callback callback)
			: this(source.Context)
		{
			Operations = source.Operations.ToList();
			Callbacks = source.Callbacks;
			AdditionalArguments = source.AdditionalArguments;
			Callbacks = (DataStorageHelper.DataStorageUpdatedHandler)Delegate.Combine(Callbacks, callback.Method);
		}

		internal DataStorageElement(DataStorageElement source, AdditionalArgument additionalArgument)
			: this(source.Context)
		{
			Operations = source.Operations.ToList();
			Callbacks = source.Callbacks;
			AdditionalArguments = source.AdditionalArguments;
			AdditionalArguments[additionalArgument.Key] = additionalArgument.Value;
		}

		public static DataStorageElement operator ++(DataStorageElement a)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(1));
		}

		public static DataStorageElement operator --(DataStorageElement a)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(-1));
		}

		public static DataStorageElement operator +(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator +(DataStorageElement a, long b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator +(DataStorageElement a, float b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator +(DataStorageElement a, double b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator +(DataStorageElement a, decimal b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator +(DataStorageElement a, string b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator +(DataStorageElement a, JToken b)
		{
			return new DataStorageElement(a, OperationType.Add, b);
		}

		public static DataStorageElement operator +(DataStorageElement a, IEnumerable b)
		{
			return new DataStorageElement(a, OperationType.Add, (JToken)(object)JArray.FromObject((object)b));
		}

		public static DataStorageElement operator +(DataStorageElement a, OperationSpecification s)
		{
			return new DataStorageElement(a, s.OperationType, s.Value);
		}

		public static DataStorageElement operator +(DataStorageElement a, Callback c)
		{
			return new DataStorageElement(a, c);
		}

		public static DataStorageElement operator +(DataStorageElement a, AdditionalArgument arg)
		{
			return new DataStorageElement(a, arg);
		}

		public static DataStorageElement operator *(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator *(DataStorageElement a, long b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator *(DataStorageElement a, float b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator *(DataStorageElement a, double b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator *(DataStorageElement a, decimal b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator %(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator %(DataStorageElement a, long b)
		{
			return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator %(DataStorageElement a, float b)
		{
			return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator %(DataStorageElement a, double b)
		{
			return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator %(DataStorageElement a, decimal b)
		{
			return new DataStorageElement(a, OperationType.Mod, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator ^(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator ^(DataStorageElement a, long b)
		{
			return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator ^(DataStorageElement a, float b)
		{
			return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator ^(DataStorageElement a, double b)
		{
			return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator ^(DataStorageElement a, decimal b)
		{
			return new DataStorageElement(a, OperationType.Pow, JToken.op_Implicit(b));
		}

		public static DataStorageElement operator -(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b)));
		}

		public static DataStorageElement operator -(DataStorageElement a, long b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b)));
		}

		public static DataStorageElement operator -(DataStorageElement a, float b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0f - b)));
		}

		public static DataStorageElement operator -(DataStorageElement a, double b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0.0 - b)));
		}

		public static DataStorageElement operator -(DataStorageElement a, decimal b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-b)));
		}

		public static DataStorageElement operator /(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b)));
		}

		public static DataStorageElement operator /(DataStorageElement a, long b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / (decimal)b)));
		}

		public static DataStorageElement operator /(DataStorageElement a, float b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / (double)b)));
		}

		public static DataStorageElement operator /(DataStorageElement a, double b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / b)));
		}

		public static DataStorageElement operator /(DataStorageElement a, decimal b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / b)));
		}

		public static implicit operator DataStorageElement(bool b)
		{
			return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(b));
		}

		public static implicit operator DataStorageElement(int i)
		{
			return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(i));
		}

		public static implicit operator DataStorageElement(long l)
		{
			return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(l));
		}

		public static implicit operator DataStorageElement(decimal m)
		{
			return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(m));
		}

		public static implicit operator DataStorageElement(double d)
		{
			return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(d));
		}

		public static implicit operator DataStorageElement(float f)
		{
			return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(f));
		}

		public static implicit operator DataStorageElement(string s)
		{
			if (s != null)
			{
				return new DataStorageElement(OperationType.Replace, JToken.op_Implicit(s));
			}
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JValue.CreateNull());
		}

		public static implicit operator DataStorageElement(JToken o)
		{
			return new DataStorageElement(OperationType.Replace, o);
		}

		public static implicit operator DataStorageElement(Array a)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)a));
		}

		public static implicit operator DataStorageElement(List<bool> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator DataStorageElement(List<int> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator DataStorageElement(List<long> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator DataStorageElement(List<decimal> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator DataStorageElement(List<double> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator DataStorageElement(List<float> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator DataStorageElement(List<string> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator DataStorageElement(List<object> l)
		{
			return new DataStorageElement(OperationType.Replace, (JToken)(object)JArray.FromObject((object)l));
		}

		public static implicit operator bool(DataStorageElement e)
		{
			return RetrieveAndReturnBoolValue<bool>(e);
		}

		public static implicit operator bool?(DataStorageElement e)
		{
			return RetrieveAndReturnBoolValue<bool?>(e);
		}

		public static implicit operator int(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<int>(e);
		}

		public static implicit operator int?(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<int?>(e);
		}

		public static implicit operator long(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<long>(e);
		}

		public static implicit operator long?(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<long?>(e);
		}

		public static implicit operator float(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<float>(e);
		}

		public static implicit operator float?(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<float?>(e);
		}

		public static implicit operator double(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<double>(e);
		}

		public static implicit operator double?(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<double?>(e);
		}

		public static implicit operator decimal(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<decimal>(e);
		}

		public static implicit operator decimal?(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<decimal?>(e);
		}

		public static implicit operator string(DataStorageElement e)
		{
			return RetrieveAndReturnStringValue(e);
		}

		public static implicit operator bool[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<bool[]>(e);
		}

		public static implicit operator int[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<int[]>(e);
		}

		public static implicit operator long[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<long[]>(e);
		}

		public static implicit operator decimal[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<decimal[]>(e);
		}

		public static implicit operator double[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<double[]>(e);
		}

		public static implicit operator float[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<float[]>(e);
		}

		public static implicit operator string[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<string[]>(e);
		}

		public static implicit operator object[](DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<object[]>(e);
		}

		public static implicit operator List<bool>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<bool>>(e);
		}

		public static implicit operator List<int>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<int>>(e);
		}

		public static implicit operator List<long>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<long>>(e);
		}

		public static implicit operator List<decimal>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<decimal>>(e);
		}

		public static implicit operator List<double>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<double>>(e);
		}

		public static implicit operator List<float>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<float>>(e);
		}

		public static implicit operator List<string>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<string>>(e);
		}

		public static implicit operator List<object>(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<List<object>>(e);
		}

		public static implicit operator Array(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<Array>(e);
		}

		public static implicit operator JArray(DataStorageElement e)
		{
			return RetrieveAndReturnArrayValue<JArray>(e);
		}

		public static implicit operator JToken(DataStorageElement e)
		{
			return e.Context.GetData(e.Context.Key);
		}

		public static DataStorageElement operator +(DataStorageElement a, BigInteger b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.Parse(b.ToString()));
		}

		public static DataStorageElement operator *(DataStorageElement a, BigInteger b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.Parse(b.ToString()));
		}

		public static DataStorageElement operator %(DataStorageElement a, BigInteger b)
		{
			return new DataStorageElement(a, OperationType.Mod, JToken.Parse(b.ToString()));
		}

		public static DataStorageElement operator ^(DataStorageElement a, BigInteger b)
		{
			return new DataStorageElement(a, OperationType.Pow, JToken.Parse(b.ToString()));
		}

		public static DataStorageElement operator -(DataStorageElement a, BigInteger b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.Parse((-b).ToString()));
		}

		public static DataStorageElement operator /(DataStorageElement a, BigInteger b)
		{
			throw new InvalidOperationException("DataStorage[Key] / BigInterger is not supported, due to loss of precision when using integer division");
		}

		public static implicit operator DataStorageElement(BigInteger bi)
		{
			return new DataStorageElement(OperationType.Replace, JToken.Parse(bi.ToString()));
		}

		public static implicit operator BigInteger(DataStorageElement e)
		{
			return RetrieveAndReturnBigIntegerValue<BigInteger>(e);
		}

		public static implicit operator BigInteger?(DataStorageElement e)
		{
			return RetrieveAndReturnBigIntegerValue<BigInteger?>(e);
		}

		private static T RetrieveAndReturnBigIntegerValue<T>(DataStorageElement e)
		{
			if (e.cachedValue != null)
			{
				if (!BigInteger.TryParse(((object)e.cachedValue).ToString(), out var result))
				{
					return default(T);
				}
				return (T)Convert.ChangeType(result, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
			}
			BigInteger result2;
			BigInteger? bigInteger = (BigInteger.TryParse(((object)e.Context.GetData(e.Context.Key)).ToString(), out result2) ? new BigInteger?(result2) : null);
			if (!bigInteger.HasValue && !IsNullable<T>())
			{
				bigInteger = Activator.CreateInstance<BigInteger>();
			}
			foreach (OperationSpecification operation in e.Operations)
			{
				if (operation.OperationType == OperationType.Floor || operation.OperationType == OperationType.Ceil)
				{
					continue;
				}
				if (!BigInteger.TryParse(((object)operation.Value).ToString(), NumberStyles.AllowLeadingSign, null, out var result3))
				{
					throw new InvalidOperationException($"DataStorage[Key] cannot be converted to BigInterger as its value its not an integer number, value: {operation.Value}");
				}
				switch (operation.OperationType)
				{
				case OperationType.Replace:
					bigInteger = result3;
					break;
				case OperationType.Add:
					bigInteger += result3;
					break;
				case OperationType.Mul:
					bigInteger *= result3;
					break;
				case OperationType.Mod:
					bigInteger %= result3;
					break;
				case OperationType.Pow:
					bigInteger = BigInteger.Pow(bigInteger.Value, (int)operation.Value);
					break;
				case OperationType.Max:
				{
					BigInteger value = result3;
					BigInteger? bigInteger2 = bigInteger;
					if (value > bigInteger2)
					{
						bigInteger = result3;
					}
					break;
				}
				case OperationType.Min:
				{
					BigInteger value = result3;
					BigInteger? bigInteger2 = bigInteger;
					if (value < bigInteger2)
					{
						bigInteger = result3;
					}
					break;
				}
				case OperationType.Xor:
					bigInteger ^= result3;
					break;
				case OperationType.Or:
					bigInteger |= result3;
					break;
				case OperationType.And:
					bigInteger &= result3;
					break;
				case OperationType.LeftShift:
					bigInteger <<= (int)operation.Value;
					break;
				case OperationType.RightShift:
					bigInteger >>= (int)operation.Value;
					break;
				}
			}
			e.cachedValue = JToken.Parse(bigInteger.ToString());
			if (!bigInteger.HasValue)
			{
				return default(T);
			}
			return (T)Convert.ChangeType(bigInteger.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
		}

		public void Initialize(JToken value)
		{
			Context.Initialize(Context.Key, value);
		}

		public void Initialize(IEnumerable value)
		{
			Context.Initialize(Context.Key, (JToken)(object)JArray.FromObject((object)value));
		}

		public Task<T> GetAsync<T>()
		{
			return GetAsync().ContinueWith((Task<JToken> r) => r.Result.ToObject<T>());
		}

		public Task<JToken> GetAsync()
		{
			return Context.GetAsync(Context.Key);
		}

		private static T RetrieveAndReturnArrayValue<T>(DataStorageElement e)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Invalid comparison between Unknown and I4
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (e.cachedValue != null)
			{
				return ((JToken)(JArray)e.cachedValue).ToObject<T>();
			}
			JArray val = (JArray)(((object)e.Context.GetData(e.Context.Key).ToObject<JArray>()) ?? ((object)new JArray()));
			foreach (OperationSpecification operation in e.Operations)
			{
				switch (operation.OperationType)
				{
				case OperationType.Add:
					if ((int)operation.Value.Type != 2)
					{
						throw new InvalidOperationException($"Cannot perform operation {OperationType.Add} on Array value, with a non Array value: {operation.Value}");
					}
					((JContainer)val).Merge((object)operation.Value);
					break;
				case OperationType.Replace:
					if ((int)operation.Value.Type != 2)
					{
						throw new InvalidOperationException($"Cannot replace Array value, with a non Array value: {operation.Value}");
					}
					val = (JArray)(((object)operation.Value.ToObject<JArray>()) ?? ((object)new JArray()));
					break;
				default:
					throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on Array value");
				}
			}
			e.cachedValue = (JToken)(object)val;
			return ((JToken)val).ToObject<T>();
		}

		private static string RetrieveAndReturnStringValue(DataStorageElement e)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Invalid comparison between Unknown and I4
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Invalid comparison between Unknown and I4
			if (e.cachedValue != null)
			{
				return (string)e.cachedValue;
			}
			JToken val = e.Context.GetData(e.Context.Key);
			string text = (((int)val.Type == 10) ? null : ((object)val).ToString());
			foreach (OperationSpecification operation in e.Operations)
			{
				switch (operation.OperationType)
				{
				case OperationType.Add:
					text += (string)operation.Value;
					break;
				case OperationType.Mul:
					if ((int)operation.Value.Type != 6)
					{
						throw new InvalidOperationException($"Cannot perform operation {OperationType.Mul} on string value, with a non interger value: {operation.Value}");
					}
					text = string.Concat(Enumerable.Repeat(text, (int)operation.Value));
					break;
				case OperationType.Replace:
					text = (string)operation.Value;
					break;
				default:
					throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on string value");
				}
			}
			if (text == null)
			{
				e.cachedValue = (JToken)(object)JValue.CreateNull();
			}
			else
			{
				e.cachedValue = JToken.op_Implicit(text);
			}
			return (string)e.cachedValue;
		}

		private static T RetrieveAndReturnBoolValue<T>(DataStorageElement e)
		{
			if (e.cachedValue != null)
			{
				return e.cachedValue.ToObject<T>();
			}
			bool? flag = e.Context.GetData(e.Context.Key).ToObject<bool?>() ?? ((bool?)Activator.CreateInstance(typeof(T)));
			foreach (OperationSpecification operation in e.Operations)
			{
				if (operation.OperationType == OperationType.Replace)
				{
					flag = (bool?)operation.Value;
					continue;
				}
				throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on boolean value");
			}
			e.cachedValue = JToken.op_Implicit(flag);
			if (!flag.HasValue)
			{
				return default(T);
			}
			return (T)Convert.ChangeType(flag.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
		}

		private static T RetrieveAndReturnDecimalValue<T>(DataStorageElement e)
		{
			if (e.cachedValue != null)
			{
				return e.cachedValue.ToObject<T>();
			}
			decimal? num = e.Context.GetData(e.Context.Key).ToObject<decimal?>();
			if (!num.HasValue && !IsNullable<T>())
			{
				num = Activator.CreateInstance<decimal>();
			}
			foreach (OperationSpecification operation in e.Operations)
			{
				switch (operation.OperationType)
				{
				case OperationType.Replace:
					num = (decimal)operation.Value;
					break;
				case OperationType.Add:
					num += (decimal?)(decimal)operation.Value;
					break;
				case OperationType.Mul:
					num *= (decimal?)(decimal)operation.Value;
					break;
				case OperationType.Mod:
					num %= (decimal?)(decimal)operation.Value;
					break;
				case OperationType.Pow:
					num = (decimal)Math.Pow((double)num.Value, (double)operation.Value);
					break;
				case OperationType.Max:
					num = Math.Max(num.Value, (decimal)operation.Value);
					break;
				case OperationType.Min:
					num = Math.Min(num.Value, (decimal)operation.Value);
					break;
				case OperationType.Xor:
					num = (long)num.Value ^ (long)operation.Value;
					break;
				case OperationType.Or:
					num = (long)num.Value | (long)operation.Value;
					break;
				case OperationType.And:
					num = (long)num.Value & (long)operation.Value;
					break;
				case OperationType.LeftShift:
					num = (long)num.Value << (int)operation.Value;
					break;
				case OperationType.RightShift:
					num = (long)num.Value >> (int)operation.Value;
					break;
				case OperationType.Floor:
					num = Math.Floor(num.Value);
					break;
				case OperationType.Ceil:
					num = Math.Ceiling(num.Value);
					break;
				}
			}
			e.cachedValue = JToken.op_Implicit(num);
			if (!num.HasValue)
			{
				return default(T);
			}
			return (T)Convert.ChangeType(num.Value, IsNullable<T>() ? Nullable.GetUnderlyingType(typeof(T)) : typeof(T));
		}

		private static bool IsNullable<T>()
		{
			if (typeof(T).IsGenericType)
			{
				return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition();
			}
			return false;
		}

		public T To<T>()
		{
			if (Operations.Count != 0)
			{
				throw new InvalidOperationException("DataStorageElement.To<T>() cannot be used together with other operations on the DataStorageElement");
			}
			return Context.GetData(Context.Key).ToObject<T>();
		}

		public override string ToString()
		{
			return (Context?.ToString() ?? "(null)") + ", (" + ListOperations() + ")";
		}

		private string ListOperations()
		{
			if (Operations != null)
			{
				return string.Join(", ", Operations.Select((OperationSpecification o) => o.ToString()).ToArray());
			}
			return "none";
		}
	}
	internal class DataStorageElementContext
	{
		internal string Key { get; set; }

		internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> AddHandler { get; set; }

		internal Action<string, DataStorageHelper.DataStorageUpdatedHandler> RemoveHandler { get; set; }

		internal Func<string, JToken> GetData { get; set; }

		internal Action<string, JToken> Initialize { get; set; }

		internal Func<string, Task<JToken>> GetAsync { get; set; }

		public override string ToString()
		{
			return "Key: " + Key;
		}
	}
	public class GameData
	{
		[JsonProperty("location_name_to_id")]
		public Dictionary<string, long> LocationLookup { get; set; } = new Dictionary<string, long>();


		[JsonProperty("item_name_to_id")]
		public Dictionary<string, long> ItemLookup { get; set; } = new Dictionary<string, long>();


		[Obsolete("use Checksum instead")]
		[JsonProperty("version")]
		public int Version { get; set; }

		[JsonProperty("checksum")]
		public string Checksum { get; set; }
	}
	public class Hint
	{
		[JsonProperty("receiving_player")]
		public int ReceivingPlayer { get; set; }

		[JsonProperty("finding_player")]
		public int FindingPlayer { get; set; }

		[JsonProperty("item")]
		public long ItemId { get; set; }

		[JsonProperty("location")]
		public long LocationId { get; set; }

		[JsonProperty("item_flags")]
		public ItemFlags ItemFlags { get; set; }

		[JsonProperty("found")]
		public bool Found { get; set; }

		[JsonProperty("entrance")]
		public string Entrance { get; set; }

		[JsonProperty("status")]
		public HintStatus Status { get; set; }
	}
	public class ItemInfo
	{
		private readonly IItemInfoResolver itemInfoResolver;

		public long ItemId { get; }

		public long LocationId { get; }

		public PlayerInfo Player { get; }

		public ItemFlags Flags { get; }

		public string ItemName => itemInfoResolver.GetItemName(ItemId, ItemGame);

		public string ItemDisplayName => ItemName ?? $"Item: {ItemId}";

		public string LocationName => itemInfoResolver.GetLocationName(LocationId, LocationGame);

		public string LocationDisplayName => LocationName ?? $"Location: {LocationId}";

		public string ItemGame { get; }

		public string LocationGame { get; }

		public ItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, PlayerInfo player)
		{
			this.itemInfoResolver = itemInfoResolver;
			ItemGame = receiverGame;
			LocationGame = senderGame;
			ItemId = item.Item;
			LocationId = item.Location;
			Flags = item.Flags;
			Player = player;
		}

		public SerializableItemInfo ToSerializable()
		{
			return new SerializableItemInfo
			{
				IsScout = (GetType() == typeof(ScoutedItemInfo)),
				ItemId = ItemId,
				LocationId = LocationId,
				PlayerSlot = Player,
				Player = Player,
				Flags = Flags,
				ItemGame = ItemGame,
				ItemName = ItemName,
				LocationGame = LocationGame,
				LocationName = LocationName
			};
		}
	}
	public class ScoutedItemInfo : ItemInfo
	{
		public new PlayerInfo Player => base.Player;

		public bool IsReceiverRelatedToActivePlayer { get; }

		public ScoutedItemInfo(NetworkItem item, string receiverGame, string senderGame, IItemInfoResolver itemInfoResolver, IPlayerHelper players, PlayerInfo player)
			: base(item, receiverGame, senderGame, itemInfoResolver, player)
		{
			IsReceiverRelatedToActivePlayer = (players.ActivePlayer ?? new PlayerInfo()).IsRelatedTo(player);
		}
	}
	public class JsonMessagePart
	{
		[JsonProperty("type")]
		[JsonConverter(typeof(AttemptingStringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })]
		public JsonMessagePartType? Type { get; set; }

		[JsonProperty("color")]
		[JsonConverter(typeof(AttemptingStringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })]
		public JsonMessagePartColor? Color { get; set; }

		[JsonProperty("text")]
		public string Text { get; set; }

		[JsonProperty("player")]
		public int? Player { get; set; }

		[JsonProperty("flags")]
		public ItemFlags? Flags { get; set; }

		[JsonProperty("hint_status")]
		public HintStatus? HintStatus { get; set; }
	}
	public struct NetworkItem
	{
		[JsonProperty("item")]
		public long Item { get; set; }

		[JsonProperty("location")]
		public long Location { get; set; }

		[JsonProperty("player")]
		public int Player { get; set; }

		[JsonProperty("flags")]
		public ItemFlags Flags { get; set; }
	}
	public struct NetworkPlayer
	{
		[JsonProperty("team")]
		public int Team { get; set; }

		[JsonProperty("slot")]
		public int Slot { get; set; }

		[JsonProperty("alias")]
		public string Alias { get; set; }

		[JsonProperty("name")]
		public string Name { get; set; }
	}
	public struct NetworkSlot
	{
		[JsonProperty("name")]
		public string Name { get; set; }

		[JsonProperty("game")]
		public string Game { get; set; }

		[JsonProperty("type")]
		public SlotType Type { get; set; }

		[JsonProperty("group_members")]
		public int[] GroupMembers { get; set; }
	}
	public class NetworkVersion
	{
		[JsonProperty("major")]
		public int Major { get; set; }

		[JsonProperty("minor")]
		public int Minor { get; set; }

		[JsonProperty("build")]
		public int Build { get; set; }

		[JsonProperty("class")]
		public string Class => "Version";

		public NetworkVersion()
		{
		}

		public NetworkVersion(int major, int minor, int build)
		{
			Major = major;
			Minor = minor;
			Build = build;
		}

		public NetworkVersion(Version version)
		{
			Major = version.Major;
			Minor = version.Minor;
			Build = version.Build;
		}

		public Version ToVersion()
		{
			return new Version(Major, Minor, Build);
		}
	}
	public class OperationSpecification
	{
		[JsonProperty("operation")]
		[JsonConverter(typeof(AttemptingStringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })]
		public OperationType OperationType;

		[JsonProperty("value")]
		public JToken Value { get; set; }

		public override string ToString()
		{
			return $"{OperationType}: {Value}";
		}
	}
	public static class Operation
	{
		public static OperationSpecification Min(int i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Min(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Min(float i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Min(double i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Min(decimal i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Min(JToken i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = i
			};
		}

		public static OperationSpecification Min(BigInteger i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = JToken.Parse(i.ToString())
			};
		}

		public static OperationSpecification Max(int i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Max(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Max(float i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Max(double i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Max(decimal i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Max(JToken i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = i
			};
		}

		public static OperationSpecification Max(BigInteger i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = JToken.Parse(i.ToString())
			};
		}

		public static OperationSpecification Remove(JToken value)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Remove,
				Value = value
			};
		}

		public static OperationSpecification Pop(int value)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Pop,
				Value = JToken.op_Implicit(value)
			};
		}

		public static OperationSpecification Pop(JToken value)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Pop,
				Value = value
			};
		}

		public static OperationSpecification Update(IDictionary dictionary)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Update,
				Value = (JToken)(object)JObject.FromObject((object)dictionary)
			};
		}

		public static OperationSpecification Floor()
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Floor,
				Value = null
			};
		}

		public static OperationSpecification Ceiling()
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Ceil,
				Value = null
			};
		}
	}
	public static class Bitwise
	{
		public static OperationSpecification Xor(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Xor,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Xor(BigInteger i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Xor,
				Value = JToken.Parse(i.ToString())
			};
		}

		public static OperationSpecification Or(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Or,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification Or(BigInteger i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Or,
				Value = JToken.Parse(i.ToString())
			};
		}

		public static OperationSpecification And(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.And,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification And(BigInteger i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.And,
				Value = JToken.Parse(i.ToString())
			};
		}

		public static OperationSpecification LeftShift(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.LeftShift,
				Value = JToken.op_Implicit(i)
			};
		}

		public static OperationSpecification RightShift(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.RightShift,
				Value = JToken.op_Implicit(i)
			};
		}
	}
	public class Callback
	{
		internal DataStorageHelper.DataStorageUpdatedHandler Method { get; set; }

		private Callback()
		{
		}

		public static Callback Add(DataStorageHelper.DataStorageUpdatedHandler callback)
		{
			return new Callback
			{
				Method = callback
			};
		}
	}
	public class AdditionalArgument
	{
		internal string Key { get; set; }

		internal JToken Value { get; set; }

		private AdditionalArgument()
		{
		}

		public static AdditionalArgument Add(string name, JToken value)
		{
			return new AdditionalArgument
			{
				Key = name,
				Value = value
			};
		}
	}
	public class MinimalSerializableItemInfo
	{
		public long ItemId { get; set; }

		public long LocationId { get; set; }

		public int PlayerSlot { get; set; }

		public ItemFlags Flags { get; set; }

		public string ItemGame { get; set; }

		public string LocationGame { get; set; }
	}
	public class SerializableItemInfo : MinimalSerializableItemInfo
	{
		public bool IsScout { get; set; }

		public PlayerInfo Player { get; set; }

		public string ItemName { get; set; }

		public string LocationName { get; set; }

		[JsonIgnore]
		public string ItemDisplayName => ItemName ?? $"Item: {base.ItemId}";

		[JsonIgnore]
		public string LocationDisplayName => LocationName ?? $"Location: {base.LocationId}";

		public string ToJson(bool full = false)
		{
			//IL_005d: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			MinimalSerializableItemInfo minimalSerializableItemInfo = this;
			if (!full)
			{
				minimalSerializableItemInfo = new MinimalSerializableItemInfo
				{
					ItemId = base.ItemId,
					LocationId = base.LocationId,
					PlayerSlot = base.PlayerSlot,
					Flags = base.Flags
				};
				if (IsScout)
				{
					minimalSerializableItemInfo.ItemGame = base.ItemGame;
				}
				else
				{
					minimalSerializableItemInfo.LocationGame = base.LocationGame;
				}
			}
			JsonSerializerSettings val = new JsonSerializerSettings
			{
				NullValueHandling = (NullValueHandling)1,
				Formatting = (Formatting)0
			};
			return JsonConvert.SerializeObject((object)minimalSerializableItemInfo, val);
		}

		public static SerializableItemInfo FromJson(string json, IArchipelagoSession session = null)
		{
			//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_0050: Expected O, but got Unknown
			ItemInfoStreamingContext additional = ((session != null) ? new ItemInfoStreamingContext
			{
				Items = session.Items,
				Locations = session.Locations,
				PlayerHelper = session.Players,
				ConnectionInfo = session.ConnectionInfo
			} : null);
			JsonSerializerSettings val = new JsonSerializerSettings
			{
				Context = new StreamingContext(StreamingContextStates.Other, additional)
			};
			return JsonConvert.DeserializeObject<SerializableItemInfo>(json, val);
		}

		[OnDeserialized]
		internal void OnDeserializedMethod(StreamingContext streamingContext)
		{
			if (base.ItemGame == null && base.LocationGame != null)
			{
				IsScout = false;
			}
			else if (base.ItemGame != null && base.LocationGame == null)
			{
				IsScout = true;
			}
			if (streamingContext.Context is ItemInfoStreamingContext itemInfoStreamingContext)
			{
				if (IsScout && base.LocationGame == null)
				{
					base.LocationGame = itemInfoStreamingContext.ConnectionInfo.Game;
				}
				else if (!IsScout && base.ItemGame == null)
				{
					base.ItemGame = itemInfoStreamingContext.ConnectionInfo.Game;
				}
				if (ItemName == null)
				{
					ItemName = itemInfoStreamingContext.Items.GetItemName(base.ItemId, base.ItemGame);
				}
				if (LocationName == null)
				{
					LocationName = itemInfoStreamingContext.Locations.GetLocationNameFromId(base.LocationId, base.LocationGame);
				}
				if (Player == null)
				{
					Player = itemInfoStreamingContext.PlayerHelper.GetPlayerInfo(base.PlayerSlot);
				}
			}
		}
	}
	internal class ItemInfoStreamingContext
	{
		public IReceivedItemsHelper Items { get; set; }

		public ILocationCheckHelper Locations { get; set; }

		public IPlayerHelper PlayerHelper { get; set; }

		public IConnectionInfoProvider ConnectionInfo { get; set; }
	}
}
namespace Archipelago.MultiClient.Net.MessageLog.Parts
{
	public class EntranceMessagePart : MessagePart
	{
		internal EntranceMessagePart(JsonMessagePart messagePart)
			: base(MessagePartType.Entrance, messagePart, Archipelago.MultiClient.Net.Colors.PaletteColor.Blue)
		{
			base.Text = messagePart.Text;
		}
	}
	public class HintStatusMessagePart : MessagePart
	{
		internal HintStatusMessagePart(JsonMessagePart messagePart)
			: base(MessagePartType.HintStatus, messagePart)
		{
			base.Text = messagePart.Text;
			if (messagePart.HintStatus.HasValue)
			{
				base.PaletteColor = ColorUtils.GetColor(messagePart.HintStatus.Value);
			}
		}
	}
	public class ItemMessagePart : MessagePart
	{
		public ItemFlags Flags { get; }

		public long ItemId { get; }

		public int Player { get; }

		internal ItemMessagePart(IPlayerHelper players, IItemInfoResolver items, JsonMessagePart part)
			: base(MessagePartType.Item, part)
		{
			Flags = part.Flags.GetValueOrDefault();
			base.PaletteColor = ColorUtils.GetColor(Flags);
			Player = part.Player.GetValueOrDefault();
			string game = (players.GetPlayerInfo(Player) ?? new PlayerInfo()).Game;
			JsonMessagePartType? type = part.Type;
			if (type.HasValue)
			{
				switch (type.GetValueOrDefault())
				{
				case JsonMessagePartType.ItemId:
					ItemId = long.Parse(part.Text);
					base.Text = items.GetItemName(ItemId, game) ?? $"Item: {ItemId}";
					break;
				case JsonMessagePartType.ItemName:
					ItemId = 0L;
					base.Text = part.Text;
					break;
				}
			}
		}
	}
	public class LocationMessagePart : MessagePart
	{
		public long LocationId { get; }

		public int Player { get; }

		internal LocationMessagePart(IPlayerHelper players, IItemInfoResolver itemInfoResolver, JsonMessagePart part)
			: base(MessagePartType.Location, part, Archipelago.MultiClient.Net.Colors.PaletteColor.Green)
		{
			Player = part.Player.GetValueOrDefault();
			string game = (players.GetPlayerInfo(Player) ?? new PlayerInfo()).Game;
			JsonMessagePartType? type = part.Type;
			if (type.HasValue)
			{
				switch (type.GetValueOrDefault())
				{
				case JsonMessagePartType.LocationId:
					LocationId = long.Parse(part.Text);
					base.Text = itemInfoResolver.GetLocationName(LocationId, game) ?? $"Location: {LocationId}";
					break;
				case JsonMessagePartType.LocationName:
					LocationId = itemInfoResolver.GetLocationId(part.Text, game);
					base.Text = part.Text;
					break;
				}
			}
		}
	}
	public class MessagePart
	{
		public string Text { get; internal set; }

		public MessagePartType Type { get; internal set; }

		public Color Color => GetColor(BuiltInPalettes.Dark);

		public PaletteColor? PaletteColor { get; protected set; }

		public bool IsBackgroundColor { get; internal set; }

		internal MessagePart(MessagePartType type, JsonMessagePart messagePart, PaletteColor? color = null)
		{
			Type = type;
			Text = messagePart.Text;
			if (color.HasValue)
			{
				PaletteColor = color.Value;
			}
			else if (messagePart.Color.HasValue)
			{
				PaletteColor = ColorUtils.GetColor(messagePart.Color.Value);
				IsBackgroundColor = messagePart.Color.Value >= JsonMessagePartColor.BlackBg;
			}
			else
			{
				PaletteColor = null;
			}
		}

		public T GetColor<T>(Palette<T> palette)
		{
			return palette[PaletteColor];
		}

		public override string ToString()
		{
			return Text;
		}
	}
	public enum MessagePartType
	{
		Text,
		Player,
		Item,
		Location,
		Entrance,
		HintStatus
	}
	public class PlayerMessagePart : MessagePart
	{
		public bool IsActivePlayer { get; }

		public int SlotId { get; }

		internal PlayerMessagePart(IPlayerHelper players, IConnectionInfoProvider connectionInfo, JsonMessagePart part)
			: base(MessagePartType.Player, part)
		{
			switch (part.Type)
			{
			case JsonMessagePartType.PlayerId:
				SlotId = int.Parse(part.Text);
				IsActivePlayer = SlotId == connectionInfo.Slot;
				base.Text = players.GetPlayerAlias(SlotId) ?? $"Player {SlotId}";
				break;
			case JsonMessagePartType.PlayerName:
				SlotId = 0;
				IsActivePlayer = false;
				base.Text = part.Text;
				break;
			}
			base.PaletteColor = (IsActivePlayer ? Archipelago.MultiClient.Net.Colors.PaletteColor.Magenta : Archipelago.MultiClient.Net.Colors.PaletteColor.Yellow);
		}
	}
}
namespace Archipelago.MultiClient.Net.MessageLog.Messages
{
	public class AdminCommandResultLogMessage : LogMessage
	{
		internal AdminCommandResultLogMessage(MessagePart[] parts)
			: base(parts)
		{
		}
	}
	public class ChatLogMessage : PlayerSpecificLogMessage
	{
		public string Message { get; }

		internal ChatLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string message)
			: base(parts, players, team, slot)
		{
			Message = message;
		}
	}
	public class CollectLogMessage : PlayerSpecificLogMessage
	{
		internal CollectLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot)
			: base(parts, players, team, slot)
		{
		}
	}
	public class CommandResultLogMessage : LogMessage
	{
		internal CommandResultLogMessage(MessagePart[] parts)
			: base(parts)
		{
		}
	}
	public class CountdownLogMessage : LogMessage
	{
		public int RemainingSeconds { get; }

		internal CountdownLogMessage(MessagePart[] parts, int remainingSeconds)
			: base(parts)
		{
			RemainingSeconds = remainingSeconds;
		}
	}
	public class GoalLogMessage : PlayerSpecificLogMessage
	{
		internal GoalLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot)
			: base(parts, players, team, slot)
		{
		}
	}
	public class HintItemSendLogMessage : ItemSendLogMessage
	{
		public bool IsFound { get; }

		internal HintItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, bool found, IItemInfoResolver itemInfoResolver)
			: base(parts, players, receiver, sender, item, itemInfoResolver)
		{
			IsFound = found;
		}
	}
	public class ItemCheatLogMessage : ItemSendLogMessage
	{
		internal ItemCheatLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, NetworkItem item, IItemInfoResolver itemInfoResolver)
			: base(parts, players, slot, 0, item, team, itemInfoResolver)
		{
		}
	}
	public class ItemSendLogMessage : LogMessage
	{
		private PlayerInfo ActivePlayer { get; }

		public PlayerInfo Receiver { get; }

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer;

		public bool IsSenderTheActivePlayer => Sender == ActivePlayer;

		public bool IsRelatedToActivePlayer
		{
			get
			{
				if (!ActivePlayer.IsRelatedTo(Receiver))
				{
					return ActivePlayer.IsRelatedTo(Sender);
				}
				return true;
			}
		}

		public ItemInfo Item { get; }

		internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, IItemInfoResolver itemInfoResolver)
			: this(parts, players, receiver, sender, item, players.ActivePlayer.Team, itemInfoResolver)
		{
		}

		internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, int receiver, int sender, NetworkItem item, int team, IItemInfoResolver itemInfoResolver)
			: base(parts)
		{
			ActivePlayer = players.ActivePlayer ?? new PlayerInfo();
			Receiver = players.GetPlayerInfo(team, receiver) ?? new PlayerInfo();
			Sender = players.GetPlayerInfo(team, sender) ?? new PlayerInfo();
			PlayerInfo player = players.GetPlayerInfo(team, item.Player) ?? new PlayerInfo();
			Item = new ItemInfo(item, Receiver.Game, Sender.Game, itemInfoResolver, player);
		}
	}
	public class JoinLogMessage : PlayerSpecificLogMessage
	{
		public string[] Tags { get; }

		internal JoinLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string[] tags)
			: base(parts, players, team, slot)
		{
			Tags = tags;
		}
	}
	public class LeaveLogMessage : PlayerSpecificLogMessage
	{
		internal LeaveLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot)
			: base(parts, players, team, slot)
		{
		}
	}
	public class LogMessage
	{
		public MessagePart[] Parts { get; }

		internal LogMessage(MessagePart[] parts)
		{
			Parts = parts;
		}

		public override string ToString()
		{
			if (Parts.Length == 1)
			{
				return Parts[0].Text;
			}
			StringBuilder stringBuilder = new StringBuilder();
			MessagePart[] parts = Parts;
			foreach (MessagePart messagePart in parts)
			{
				stringBuilder.Append(messagePart.Text);
			}
			return stringBuilder.ToString();
		}
	}
	public abstract class PlayerSpecificLogMessage : LogMessage
	{
		private PlayerInfo ActivePlayer { get; }

		public PlayerInfo Player { get; }

		public bool IsActivePlayer => Player == ActivePlayer;

		public bool IsRelatedToActivePlayer => ActivePlayer.IsRelatedTo(Player);

		internal PlayerSpecificLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot)
			: base(parts)
		{
			ActivePlayer = players.ActivePlayer ?? new PlayerInfo();
			Player = players.GetPlayerInfo(team, slot) ?? new PlayerInfo();
		}
	}
	public class ReleaseLogMessage : PlayerSpecificLogMessage
	{
		internal ReleaseLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot)
			: base(parts, players, team, slot)
		{
		}
	}
	public class ServerChatLogMessage : LogMessage
	{
		public string Message { get; }

		internal ServerChatLogMessage(MessagePart[] parts, string message)
			: base(parts)
		{
			Message = message;
		}
	}
	public class TagsChangedLogMessage : PlayerSpecificLogMessage
	{
		public string[] Tags { get; }

		internal TagsChangedLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string[] tags)
			: base(parts, players, team, slot)
		{
			Tags = tags;
		}
	}
	public class TutorialLogMessage : LogMessage
	{
		internal TutorialLogMessage(MessagePart[] parts)
			: base(parts)
		{
		}
	}
}
namespace Archipelago.MultiClient.Net.Helpers
{
	public class ArchipelagoSocketHelper : BaseArchipelagoSocketHelper<ClientWebSocket>, IArchipelagoSocketHelper
	{
		public Uri Uri { get; }

		internal ArchipelagoSocketHelper(Uri hostUri)
			: base(CreateWebSocket(), 1024)
		{
			Uri = hostUri;
			SecurityProtocolType securityProtocolType = SecurityProtocolType.Tls13;
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | securityProtocolType;
		}

		private static ClientWebSocket CreateWebSocket()
		{
			return new ClientWebSocket();
		}

		public async Task ConnectAsync()
		{
			await ConnectToProvidedUri(Uri);
			StartPolling();
		}

		private async Task ConnectToProvidedUri(Uri uri)
		{
			if (uri.Scheme != "unspecified")
			{
				try
				{
					await Socket.ConnectAsync(uri, CancellationToken.None);
					return;
				}
				catch (Exception e)
				{
					OnError(e);
					throw;
				}
			}
			List<Exception> errors = new List<Exception>(0);
			try
			{
				await Socket.ConnectAsync(uri.AsWss(), CancellationToken.None);
				if (Socket.State == WebSocketState.Open)
				{
					return;
				}
			}
			catch (Exception item)
			{
				errors.Add(item);
				Socket = CreateWebSocket();
			}
			try
			{
				await Socket.ConnectAsync(uri.AsWs(), CancellationToken.None);
			}
			catch (Exception item2)
			{
				errors.Add(item2);
				OnError(new AggregateException(errors));
				throw;
			}
		}
	}
	public class BaseArchipelagoSocketHelper<T> where T : WebSocket
	{
		private static readonly ArchipelagoPacketConverter Converter = new ArchipelagoPacketConverter();

		private readonly BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>> sendQueue = new BlockingCollection<Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>>();

		internal T Socket;

		private readonly int bufferSize;

		public bool Connected
		{
			get
			{
				if (Socket.State != WebSocketState.Open)
				{
					return Socket.State == WebSocketState.CloseReceived;
				}
				return true;
			}
		}

		public event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived;

		public event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent;

		public event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived;

		public event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed;

		public event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened;

		internal BaseArchipelagoSocketHelper(T socket, int bufferSize = 1024)
		{
			Socket = socket;
			this.bufferSize = bufferSize;
		}

		internal void StartPolling()
		{
			if (this.SocketOpened != null)
			{
				this.SocketOpened();
			}
			Task.Run((Func<Task?>)PollingLoop);
			Task.Run((Func<Task?>)SendLoop);
		}

		private async Task PollingLoop()
		{
			byte[] buffer = new byte[bufferSize];
			while (Socket.State == WebSocketState.Open)
			{
				string message = null;
				try
				{
					message = await ReadMessageAsync(buffer);
				}
				catch (Exception e)
				{
					OnError(e);
				}
				OnMessageReceived(message);
			}
		}

		private async Task SendLoop()
		{
			while (Socket.State == WebSocketState.Open)
			{
				try
				{
					await HandleSendBuffer();
				}
				catch (Exception e)
				{
					OnError(e);
				}
				await Task.Delay(20);
			}
		}

		private async Task<string> ReadMessageAsync(byte[] buffer)
		{
			using MemoryStream readStream = new MemoryStream(buffer.Length);
			WebSocketReceiveResult result;
			do
			{
				result = await Socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
				if (result.MessageType == WebSocketMessageType.Close)
				{
					try
					{
						await Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
					}
					catch
					{
					}
					OnSocketClosed();
				}
				else
				{
					readStream.Write(buffer, 0, result.Count);
				}
			}
			while (!result.EndOfMessage);
			return Encoding.UTF8.GetString(readStream.ToArray());
		}

		public async Task DisconnectAsync()
		{
			await Socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closure requested by client", CancellationToken.None);
			OnSocketClosed();
		}

		public void SendPacket(ArchipelagoPacketBase packet)
		{
			SendMultiplePackets(new List<ArchipelagoPacketBase> { packet });
		}

		public void SendMultiplePackets(List<ArchipelagoPacketBase> packets)
		{
			SendMultiplePackets(packets.ToArray());
		}

		public void SendMultiplePackets(params ArchipelagoPacketBase[] packets)
		{
			SendMultiplePacketsAsync(packets).Wait();
		}

		public Task SendPacketAsync(ArchipelagoPacketBase packet)
		{
			return SendMultiplePacketsAsync(new List<ArchipelagoPacketBase> { packet });
		}

		public Task SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets)
		{
			return SendMultiplePacketsAsync(packets.ToArray());
		}

		public Task SendMultiplePacketsAsync(params ArchipelagoPacketBase[] packets)
		{
			TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();
			foreach (ArchipelagoPacketBase item in packets)
			{
				sendQueue.Add(new Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>>(item, taskCompletionSource));
			}
			return taskCompletionSource.Task;
		}

		private async Task HandleSendBuffer()
		{
			List<ArchipelagoPacketBase> list = new List<ArchipelagoPacketBase>();
			List<TaskCompletionSource<bool>> tasks = new List<TaskCompletionSource<bool>>();
			Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>> tuple = sendQueue.Take();
			list.Add(tuple.Item1);
			tasks.Add(tuple.Item2);
			Tuple<ArchipelagoPacketBase, TaskCompletionSource<bool>> item;
			while (sendQueue.TryTake(out item))
			{
				list.Add(item.Item1);
				tasks.Add(item.Item2);
			}
			if (!list.Any())
			{
				return;
			}
			if (Socket.State != WebSocketState.Open)
			{
				throw new ArchipelagoSocketClosedException();
			}
			ArchipelagoPacketBase[] packets = list.ToArray();
			string s = JsonConvert.SerializeObject((object)packets);
			byte[] messageBuffer = Encoding.UTF8.GetBytes(s);
			int messagesCount = (int)Math.Ceiling((double)messageBuffer.Length / (double)bufferSize);
			for (int i = 0; i < messagesCount; i++)
			{
				int num = bufferSize * i;
				int num2 = bufferSize;
				bool endOfMessage = i + 1 == messagesCount;
				if (num2 * (i + 1) > messageBuffer.Length)
				{
					num2 = messageBuffer.Length - num;
				}
				await Socket.SendAsync(new ArraySegment<byte>(messageBuffer, num, num2), WebSocketMessageType.Text, endOfMessage, CancellationToken.None);
			}
			foreach (TaskCompletionSource<bool> item2 in tasks)
			{
				item2.TrySetResult(result: true);
			}
			OnPacketSend(packets);
		}

		private void OnPacketSend(ArchipelagoPacketBase[] packets)
		{
			try
			{
				if (this.PacketsSent != null)
				{
					this.PacketsSent(packets);
				}
			}
			catch (Exception e)
			{
				OnError(e);
			}
		}

		private void OnSocketClosed()
		{
			try
			{
				if (this.SocketClosed != null)
				{
					this.SocketClosed("");
				}
			}
			catch (Exception e)
			{
				OnError(e);
			}
		}

		private void OnMessageReceived(string message)
		{
			try
			{
				if (string.IsNullOrEmpty(message) || this.PacketReceived == null)
				{
					return;
				}
				List<ArchipelagoPacketBase> list = null;
				try
				{
					list = JsonConvert.DeserializeObject<List<ArchipelagoPacketBase>>(message, (JsonConverter[])(object)new JsonConverter[1] { Converter });
				}
				catch (Exception e)
				{
					OnError(e);
				}
				if (list == null)
				{
					return;
				}
				foreach (ArchipelagoPacketBase item in list)
				{
					this.PacketReceived(item);
				}
			}
			catch (Exception e2)
			{
				OnError(e2);
			}
		}

		protected void OnError(Exception e)
		{
			try
			{
				if (this.ErrorReceived != null)
				{
					this.ErrorReceived(e, e.Message);
				}
			}
			catch (Exception ex)
			{
				Console.Out.WriteLine("Error occured during reporting of errorOuter Errror: " + e.Message + " " + e.StackTrace + "Inner Errror: " + ex.Message + " " + ex.StackTrace);
			}
		}
	}
	public interface IConnectionInfoProvider
	{
		string Game { get; }

		int Team { get; }

		int Slot { get; }

		string[] Tags { get; }

		ItemsHandlingFlags ItemsHandlingFlags { get; }

		string Uuid { get; }

		void UpdateConnectionOptions(string[] tags);

		void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags);

		void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags);
	}
	public class ConnectionInfoHelper : IConnectionInfoProvider
	{
		private readonly IArchipelagoSocketHelper socket;

		public string Game { get; private set; }

		public int Team { get; private set; }

		public int Slot { get; private set; }

		public string[] Tags { get; internal set; }

		public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; }

		public string Uuid { get; private set; }

		internal ConnectionInfoHelper(IArchipelagoSocketHelper socket)
		{
			this.socket = socket;
			Reset();
			socket.PacketReceived += PacketReceived;
		}

		private void PacketReceived(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket connectedPacket))
			{
				if (packet is ConnectionRefusedPacket)
				{
					Reset();
				}
				return;
			}
			Team = connectedPacket.Team;
			Slot = connectedPacket.Slot;
			if (connectedPacket.SlotInfo != null && connectedPacket.SlotInfo.ContainsKey(Slot))
			{
				Game = connectedPacket.SlotInfo[Slot].Game;
			}
		}

		internal void SetConnectionParameters(string game, string[] tags, ItemsHandlingFlags itemsHandlingFlags, string uuid)
		{
			Game = game;
			Tags = tags ?? new string[0];
			ItemsHandlingFlags = itemsHandlingFlags;
			Uuid = uuid ?? Guid.NewGuid().ToString();
		}

		private void Reset()
		{
			Game = null;
			Team = -1;
			Slot = -1;
			Tags = new string[0];
			ItemsHandlingFlags = ItemsHandlingFlags.NoItems;
			Uuid = null;
		}

		public void UpdateConnectionOptions(string[] tags)
		{
			UpdateConnectionOptions(tags, ItemsHandlingFlags);
		}

		public void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags)
		{
			UpdateConnectionOptions(Tags, itemsHandlingFlags);
		}

		public void UpdateConnectionOptions(string[] tags, ItemsHandlingFlags itemsHandlingFlags)
		{
			SetConnectionParameters(Game, tags, itemsHandlingFlags, Uuid);
			socket.SendPacket(new ConnectUpdatePacket
			{
				Tags = Tags,
				ItemsHandling = ItemsHandlingFlags
			});
		}
	}
	public interface IDataStorageHelper : IDataStorageWrapper
	{
		DataStorageElement this[Scope scope, string key] { get; set; }

		DataStorageElement this[string key] { get; set; }
	}
	public class DataStorageHelper : IDataStorageHelper, IDataStorageWrapper
	{
		public delegate void DataStorageUpdatedHandler(JToken originalValue, JToken newValue, Dictionary<string, JToken> additionalArguments);

		private readonly Dictionary<string, DataStorageUpdatedHandler> onValueChangedEventHandlers = new Dictionary<string, DataStorageUpdatedHandler>();

		private readonly Dictionary<Guid, DataStorageUpdatedHandler> operationSpecificCallbacks = new Dictionary<Guid, DataStorageUpdatedHandler>();

		private readonly Dictionary<string, TaskCompletionSource<JToken>> asyncRetrievalTasks = new Dictionary<string, TaskCompletionSource<JToken>>();

		private readonly IArchipelagoSocketHelper socket;

		private readonly IConnectionInfoProvider connectionInfoProvider;

		public DataStorageElement this[Scope scope, string key]
		{
			get
			{
				return this[AddScope(scope, key)];
			}
			set
			{
				this[AddScope(scope, key)] = value;
			}
		}

		public DataStorageElement this[string key]
		{
			get
			{
				return new DataStorageElement(GetContextForKey(key));
			}
			set
			{
				SetValue(key, value);
			}
		}

		internal DataStorageHelper(IArchipelagoSocketHelper socket, IConnectionInfoProvider connectionInfoProvider)
		{
			this.socket = socket;
			this.connectionInfoProvider = connectionInfoProvider;
			socket.PacketReceived += OnPacketReceived;
		}

		private void OnPacketReceived(ArchipelagoPacketBase packet)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Invalid comparison between Unknown and I4
			if (!(packet is RetrievedPacket retrievedPacket))
			{
				if (packet is SetReplyPacket setReplyPacket)
				{
					if (setReplyPacket.AdditionalArguments != null && setReplyPacket.AdditionalArguments.ContainsKey("Reference") && (int)setReplyPacket.AdditionalArguments["Reference"].Type == 8 && ((string)setReplyPacket.AdditionalArguments["Reference"]).TryParseNGuid(out var g) && operationSpecificCallbacks.TryGetValue(g, out var value))
					{
						value(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments);
						operationSpecificCallbacks.Remove(g);
					}
					if (onValueChangedEventHandlers.TryGetValue(setReplyPacket.Key, out var value2))
					{
						value2(setReplyPacket.OriginalValue, setReplyPacket.Value, setReplyPacket.AdditionalArguments);
					}
				}
				return;
			}
			foreach (KeyValuePair<string, JToken> datum in retrievedPacket.Data)
			{
				if (asyncRetrievalTasks.TryGetValue(datum.Key, out var value3))
				{
					value3.TrySetResult(datum.Value);
					asyncRetrievalTasks.Remove(datum.Key);
				}
			}
		}

		private Task<JToken> GetAsync(string key)
		{
			if (asyncRetrievalTasks.TryGetValue(key, out var value))
			{
				return value.Task;
			}
			TaskCompletionSource<JToken> taskCompletionSource = new TaskCompletionSource<JToken>();
			asyncRetrievalTasks[key] = taskCompletionSource;
			socket.SendPacketAsync(new GetPacket
			{
				Keys = new string[1] { key }
			});
			return taskCompletionSource.Task;
		}

		private void Initialize(string key, JToken value)
		{
			socket.SendPacketAsync(new SetPacket
			{
				Key = key,
				DefaultValue = value,
				Operations = new OperationSpecification[1]
				{
					new OperationSpecification
					{
						OperationType = OperationType.Default
					}
				}
			});
		}

		private JToken GetValue(string key)
		{
			Task<JToken> async = GetAsync(key);
			if (!async.Wait(TimeSpan.FromSeconds(2.0)))
			{
				throw new TimeoutException("Timed out retrieving data for key `" + key + "`. This may be due to an attempt to retrieve a value from the DataStorageHelper in a synchronous fashion from within a PacketReceived handler. When using the DataStorageHelper from within code which runs on the websocket thread then use the asynchronous getters. Ex: `DataStorageHelper[\"" + key + "\"].GetAsync().ContinueWith(x => {});`Be aware that DataStorageHelper calls tend to cause packet responses, so making a call from within a PacketReceived handler may cause an infinite loop.");
			}
			return async.Result;
		}

		private void SetValue(string key, DataStorageElement e)
		{
			if (key.StartsWith("_read_"))
			{
				throw new InvalidOperationException("DataStorage write operation on readonly key '" + key + "' is not allowed");
			}
			if (e == null)
			{
				e = new DataStorageElement(OperationType.Replace, (JToken)(object)JValue.CreateNull());
			}
			if (e.Context == null)
			{
				e.Context = GetContextForKey(key);
			}
			else if (e.Context.Key != key)
			{
				e.Operations.Insert(0, new OperationSpecification
				{
					OperationType = OperationType.Replace,
					Value = GetValue(e.Context.Key)
				});
			}
			Dictionary<string, JToken> dictionary = e.AdditionalArguments ?? new Dictionary<string, JToken>(0);
			if (e.Callbacks != null)
			{
				Guid key2 = Guid.NewGuid();
				operationSpecificCallbacks[key2] = e.Callbacks;
				dictionary["Reference"] = JToken.op_Implicit(key2.ToString("N"));
				socket.SendPacketAsync(new SetPacket
				{
					Key = key,
					Operations = e.Operations.ToArray(),
					WantReply = true,
					AdditionalArguments = dictionary
				});
			}
			else
			{
				socket.SendPacketAsync(new SetPacket
				{
					Key = key,
					Operations = e.Operations.ToArray(),
					AdditionalArguments = dictionary
				});
			}
		}

		private DataStorageElementContext GetContextForKey(string key)
		{
			return new DataStorageElementContext
			{
				Key = key,
				GetData = GetValue,
				GetAsync = GetAsync,
				Initialize = Initialize,
				AddHandler = AddHandler,
				RemoveHandler = RemoveHandler
			};
		}

		private void AddHandler(string key, DataStorageUpdatedHandler handler)
		{
			if (onValueChangedEventHandlers.ContainsKey(key))
			{
				Dictionary<string, DataStorageUpdatedHandler> dictionary = onValueChangedEventHandlers;
				dictionary[key] = (DataStorageUpdatedHandler)Delegate.Combine(dictionary[key], handler);
			}
			else
			{
				onValueChangedEventHandlers[key] = handler;
			}
			socket.SendPacketAsync(new SetNotifyPacket
			{
				Keys = new string[1] { key }
			});
		}

		private void RemoveHandler(string key, DataStorageUpdatedHandler handler)
		{
			if (onValueChangedEventHandlers.ContainsKey(key))
			{
				Dictionary<string, DataStorageUpdatedHandler> dictionary = onValueChangedEventHandlers;
				dictionary[key] = (DataStorageUpdatedHandler)Delegate.Remove(dictionary[key], handler);
				if (onValueChangedEventHandlers[key] == null)
				{
					onValueChangedEventHandlers.Remove(key);
				}
			}
		}

		private string AddScope(Scope scope, string key)
		{
			return scope switch
			{
				Scope.Global => key, 
				Scope.Game => $"{scope}:{connectionInfoProvider.Game}:{key}", 
				Scope.Team => $"{scope}:{connectionInfoProvider.Team}:{key}", 
				Scope.Slot => $"{scope}:{connectionInfoProvider.Slot}:{key}", 
				Scope.ReadOnly => "_read_" + key, 
				_ => throw new ArgumentOutOfRangeException("scope", scope, "Invalid scope for key " + key), 
			};
		}

		private DataStorageElement GetHintsElement(int? slot = null, int? team = null)
		{
			return this[Scope.ReadOnly, $"hints_{team ?? connectionInfoProvider.Team}_{slot ?? connectionInfoProvider.Slot}"];
		}

		private DataStorageElement GetSlotDataElement(int? slot = null)
		{
			return this[Scope.ReadOnly, $"slot_data_{slot ?? connectionInfoProvider.Slot}"];
		}

		private DataStorageElement GetItemNameGroupsElement(string game = null)
		{
			return this[Scope.ReadOnly, "item_name_groups_" + (game ?? connectionInfoProvider.Game)];
		}

		private DataStorageElement GetLocationNameGroupsElement(string game = null)
		{
			return this[Scope.ReadOnly, "location_name_groups_" + (game ?? connectionInfoProvider.Game)];
		}

		private DataStorageElement GetClientStatusElement(int? slot = null, int? team = null)
		{
			return this[Scope.ReadOnly, $"client_status_{team ?? connectionInfoProvider.Team}_{slot ?? connectionInfoProvider.Slot}"];
		}

		private DataStorageElement GetRaceModeElement()
		{
			return this[Scope.ReadOnly, "race_mode"];
		}

		public Hint[] GetHints(int? slot = null, int? team = null)
		{
			return GetHintsElement(slot, team).To<Hint[]>();
		}

		public Task<Hint[]> GetHintsAsync(int? slot = null, int? team = null)
		{
			return GetHintsElement(slot, team).GetAsync<Hint[]>();
		}

		public void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null)
		{
			GetHintsElement(slot, team).OnValueChanged += delegate(JToken _, JToken newValue, Dictionary<string, JToken> x)
			{
				onHintsUpdated(newValue.ToObject<Hint[]>());
			};
			if (retrieveCurrentlyUnlockedHints)
			{
				GetHintsAsync(slot, team).ContinueWith(delegate(Task<Hint[]> t)
				{
					onHintsUpdated(t.Result);
				});
			}
		}

		public Dictionary<string, object> GetSlotData(int? slot = null)
		{
			return GetSlotData<Dictionary<string, object>>(slot);
		}

		public T GetSlotData<T>(int? slot = null) where T : class
		{
			return GetSlotDataElement(slot).To<T>();
		}

		public Task<Dictionary<string, object>> GetSlotDataAsync(int? slot = null)
		{
			return GetSlotDataAsync<Dictionary<string, object>>(slot);
		}

		public Task<T> GetSlotDataAsync<T>(int? slot = null) where T : class
		{
			return GetSlotDataElement(slot).GetAsync<T>();
		}

		public Dictionary<string, string[]> GetItemNameGroups(string game = null)
		{
			return GetItemNameGroupsElement(game).To<Dictionary<string, string[]>>();
		}

		public Task<Dictionary<string, string[]>> GetItemNameGroupsAsync(string game = null)
		{
			return GetItemNameGroupsElement(game).GetAsync<Dictionary<string, string[]>>();
		}

		public Dictionary<string, string[]> GetLocationNameGroups(string game = null)
		{
			return GetLocationNameGroupsElement(game).To<Dictionary<string, string[]>>();
		}

		public Task<Dictionary<string, string[]>> GetLocationNameGroupsAsync(string game = null)
		{
			return GetLocationNameGroupsElement(game).GetAsync<Dictionary<string, string[]>>();
		}

		public ArchipelagoClientState GetClientStatus(int? slot = null, int? team = null)
		{
			return GetClientStatusElement(slot, team).To<ArchipelagoClientState?>().GetValueOrDefault();
		}

		public Task<ArchipelagoClientState> GetClientStatusAsync(int? slot = null, int? team = null)
		{
			return GetClientStatusElement(slot, team).GetAsync<ArchipelagoClientState?>().ContinueWith((Task<ArchipelagoClientState?> r) => r.Result.GetValueOrDefault());
		}

		public void TrackClientStatus(Action<ArchipelagoClientState> onStatusUpdated, bool retrieveCurrentClientStatus = true, int? slot = null, int? team = null)
		{
			Get

ArchipelagoULTRAKILL.dll

Decompiled 10 hours ago
using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.BounceFeatures.DeathLink;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using ArchipelagoULTRAKILL.Commands;
using ArchipelagoULTRAKILL.Components;
using ArchipelagoULTRAKILL.Config;
using ArchipelagoULTRAKILL.Music;
using ArchipelagoULTRAKILL.Powerups;
using ArchipelagoULTRAKILL.Properties;
using ArchipelagoULTRAKILL.Structures;
using BepInEx;
using BepInEx.Logging;
using GameConsole;
using HarmonyLib;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PluginConfig.API;
using PluginConfig.API.Decorators;
using PluginConfig.API.Fields;
using PluginConfig.API.Functionals;
using TMPro;
using ULTRAKILL.Cheats;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using plog;
using plog.Models;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ArchipelagoULTRAKILL")]
[assembly: AssemblyDescription("Connect to an Archipelago server to play ULTRAKILL randomizer.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ArchipelagoULTRAKILL")]
[assembly: AssemblyCopyright("Copyright © TRPG 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c7de03cb-cf51-44da-ba1f-6fcecd638e0a")]
[assembly: AssemblyFileVersion("3.5.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("3.5.0.0")]
namespace ArchipelagoULTRAKILL
{
	public static class ColorRandomizer
	{
		public static void RandomizeGunColors()
		{
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", true);
			for (int i = 1; i <= 5; i++)
			{
				for (int j = 1; j <= 2; j++)
				{
					if (j != 2 || (i != 4 && i != 5))
					{
						bool flag = false;
						if (j == 2)
						{
							flag = true;
						}
						for (int k = 1; k <= 3; k++)
						{
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"r"
							}), Random.Range(0f, 1f));
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"g"
							}), Random.Range(0f, 1f));
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"b"
							}), Random.Range(0f, 1f));
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"a"
							}), Random.Range(0f, 1f));
						}
					}
				}
			}
			if (Core.IsPlaying)
			{
				MonoSingleton<GunColorController>.Instance.UpdateGunColors();
				GunColorTypeGetter[] array = Object.FindObjectsOfType<GunColorTypeGetter>();
				foreach (GunColorTypeGetter val in array)
				{
					val.UpdatePreview();
				}
			}
		}

		public static void RandomizeUIColors()
		{
			for (int i = 1; i <= 3; i++)
			{
				string text = ".r";
				if (i == 2)
				{
					text = ".g";
				}
				if (i == 3)
				{
					text = ".b";
				}
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hp" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hptext" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hpaft" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hphdmg" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.hpover" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.stm" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.stmchr" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.stmemp" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.raifull" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.raicha" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var0" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var1" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var2" + text, Random.Range(0f, 1f));
				MonoSingleton<PrefsManager>.Instance.SetFloat("hudColor.var3" + text, Random.Range(0f, 1f));
			}
			if (Core.IsPlaying)
			{
				MonoSingleton<ColorBlindSettings>.Instance.UpdateHudColors();
				MonoSingleton<ColorBlindSettings>.Instance.UpdateWeaponColors();
			}
		}
	}
	public static class LevelManager
	{
		public static Dictionary<string, GameObject> skulls = new Dictionary<string, GameObject>();

		public static Door redDoor;

		public static void FindSkulls()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Invalid comparison between Unknown and I4
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Invalid comparison between Unknown and I4
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Invalid comparison between Unknown and I4
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Invalid comparison between Unknown and I4
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Invalid comparison between Unknown and I4
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Invalid comparison between Unknown and I4
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Invalid comparison between Unknown and I4
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Invalid comparison between Unknown and I4
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Invalid comparison between Unknown and I4
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Invalid comparison between Unknown and I4
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Invalid comparison between Unknown and I4
			skulls.Clear();
			int num = 0;
			ItemIdentifier[] array = Resources.FindObjectsOfTypeAll<ItemIdentifier>();
			foreach (ItemIdentifier val in array)
			{
				if ((int)val.itemType != 1 && (int)val.itemType != 2)
				{
					continue;
				}
				Scene val2 = ((Component)val).gameObject.scene;
				string name = ((Scene)(ref val2)).name;
				val2 = SceneManager.GetActiveScene();
				if (!(name == ((Scene)(ref val2)).name))
				{
					continue;
				}
				if (SceneHelper.CurrentScene == "Level 2-4")
				{
					if ((Object)(object)((Component)val).gameObject.transform.parent == (Object)null || ((Object)((Component)val).gameObject.transform.parent.parent).name != "Altar (1)")
					{
						continue;
					}
				}
				else if (SceneHelper.CurrentScene == "Level 7-S")
				{
					if (((int)val.itemType == 1 && !Object.op_Implicit((Object)(object)((Component)val).transform.parent.parent.parent)) || ((int)val.itemType == 2 && ((Object)((Component)val).transform.parent.parent.parent).name != "Interactives"))
					{
						continue;
					}
				}
				else if (SceneHelper.CurrentScene == "Level 8-1")
				{
					if (((Object)((Component)val).gameObject.transform.parent.parent.parent).name != "Inside")
					{
						continue;
					}
				}
				else if (SceneHelper.CurrentScene == "Level 8-2")
				{
					if (((int)val.itemType == 1 && ((Object)((Component)val).transform.parent.parent).name != "Altar (Blue) (1)") || ((int)val.itemType == 2 && ((Object)((Component)val).transform.parent.parent).name != "Altar (Red) (1)"))
					{
						continue;
					}
				}
				else if (SceneHelper.CurrentScene == "Level 8-3")
				{
					if (((Object)((Component)val).gameObject.transform.parent.parent.parent).name == "10 Nonstuff")
					{
						continue;
					}
				}
				else if (SceneHelper.CurrentScene == "Level 8-4")
				{
					if (((int)val.itemType == 1 && ((Object)((Component)val).transform.parent).name != "Bathroom") || ((int)val.itemType == 2 && ((Object)((Component)val).transform.parent.parent).name != "Altar (Red)"))
					{
						continue;
					}
				}
				else if (SceneHelper.CurrentScene == "Level 0-E")
				{
					if (((int)val.itemType == 1 && Object.op_Implicit((Object)(object)((Component)val).transform.parent.parent.parent)) || ((int)val.itemType == 2 && Object.op_Implicit((Object)(object)((Component)val).transform.parent.parent.parent)))
					{
						continue;
					}
				}
				else if (SceneHelper.CurrentScene == "Level 1-E" && (((int)val.itemType == 1 && ((Object)((Component)val).transform.parent.parent).name != "Altar (Blue) (1)") || (int)val.itemType == 2))
				{
					continue;
				}
				if (skulls.ContainsKey(((object)(ItemType)(ref val.itemType)).ToString()))
				{
					num++;
					skulls[((object)(ItemType)(ref val.itemType)).ToString() + num] = ((Component)val).gameObject;
				}
				else
				{
					skulls[((object)(ItemType)(ref val.itemType)).ToString()] = ((Component)val).gameObject;
				}
			}
			for (int j = 0; j < skulls.Count; j++)
			{
				KeyValuePair<string, GameObject> keyValuePair = skulls.ElementAt(j);
				string text = Core.CurrentLevelInfo.Id.ToString();
				if (Core.CurrentLevelInfo.Name == "0-S")
				{
					text = "0S";
				}
				else if (Core.CurrentLevelInfo.Name == "7-S")
				{
					text = "7S";
				}
				string currentScene = SceneHelper.CurrentScene;
				string text2 = currentScene;
				if (!(text2 == "Level 1-4"))
				{
					if (text2 == "Level 5-1")
					{
						if (j + 1 > Core.data.unlockedSkulls5_1)
						{
							DeactivateSkull(keyValuePair.Value);
						}
					}
					else if (((Object)keyValuePair.Value).name.Contains("Blue"))
					{
						if (!Core.data.unlockedSkulls.Contains(text + "_b"))
						{
							DeactivateSkull(keyValuePair.Value);
						}
					}
					else if (((Object)keyValuePair.Value).name.Contains("Red") && !Core.data.unlockedSkulls.Contains(text + "_r"))
					{
						DeactivateSkull(keyValuePair.Value);
					}
				}
				else if (j + 1 > Core.data.unlockedSkulls1_4)
				{
					DeactivateSkull(keyValuePair.Value);
				}
			}
		}

		public static void ActivateSkull(GameObject skull)
		{
			ItemPlaceZone val = default(ItemPlaceZone);
			if (((Component)skull.transform.parent).TryGetComponent<ItemPlaceZone>(ref val))
			{
				val.elementChangeEffect.Play();
				InstantiateObject[] altarElements = val.altarElements;
				foreach (InstantiateObject val2 in altarElements)
				{
					((Component)val2).gameObject.SetActive(true);
					if (((Component)val2).gameObject.activeInHierarchy)
					{
						val2.Instantiate();
					}
				}
			}
			else
			{
				Core.Logger.LogWarning((object)(((Object)skull).name + " GameObject has no ItemPlaceZone in parent"));
			}
			skull.SetActive(true);
		}

		public static void DeactivateSkull(GameObject skull)
		{
			ItemPlaceZone val = default(ItemPlaceZone);
			if (((Component)skull.transform.parent).TryGetComponent<ItemPlaceZone>(ref val))
			{
				InstantiateObject[] altarElements = val.altarElements;
				foreach (InstantiateObject val2 in altarElements)
				{
					((Component)val2).gameObject.SetActive(false);
				}
			}
			else
			{
				Core.Logger.LogWarning((object)(((Object)skull).name + " GameObject has no ItemPlaceZone in parent"));
			}
			skull.SetActive(false);
		}

		public static void AddDoorClosers()
		{
			ItemPlaceZone[] array = Resources.FindObjectsOfTypeAll<ItemPlaceZone>();
			foreach (ItemPlaceZone val in array)
			{
				if (SceneHelper.CurrentScene == "Level 1-1")
				{
					if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "11 Nonstuff")
					{
						GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent.parent.parent).gameObject);
					}
				}
				else if (SceneHelper.CurrentScene == "Level 1-2")
				{
					if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "3 Nonstuff")
					{
						GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent.parent.parent).gameObject);
					}
				}
				else if (SceneHelper.CurrentScene == "Level 2-3")
				{
					if ((Object)(object)((Component)val).transform.parent != (Object)null && (((Object)((Component)val).transform.parent).name == "Altar" || ((Object)((Component)val).transform.parent).name == "Altar (1)"))
					{
						GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent).gameObject);
					}
				}
				else if (SceneHelper.CurrentScene == "Level 4-4")
				{
					if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "Secret Hall")
					{
						GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent.parent.parent).gameObject);
					}
				}
				else if (SceneHelper.CurrentScene == "Level 5-2")
				{
					if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && (((Object)((Component)val).transform.parent.parent).name == "6" || ((Object)((Component)val).transform.parent.parent).name == "7B"))
					{
						GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent.parent).gameObject);
					}
				}
				else if (SceneHelper.CurrentScene == "Level 5-3")
				{
					if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "2A4 - Skullway")
					{
						GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent.parent).gameObject);
					}
				}
				else if (SceneHelper.CurrentScene == "Level 6-1")
				{
					if ((Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "3 - Crossroads")
					{
						GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent.parent).gameObject);
					}
				}
				else if (SceneHelper.CurrentScene == "Level 1-E" && (Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "13-3 Connector")
				{
					GameObjectExtensions.GetOrAddComponent<ReverseDoorCloser>(((Component)((Component)val).transform.parent.parent).gameObject);
				}
			}
		}

		public static void DeactivateNailgun()
		{
			GearCheckEnabler[] array = Resources.FindObjectsOfTypeAll<GearCheckEnabler>();
			foreach (GearCheckEnabler val in array)
			{
				if (((Object)((Component)val).transform.parent).name == "1 - First Room")
				{
					((Component)val).gameObject.SetActive(false);
				}
			}
		}

		public static void ChangeIntro()
		{
			//IL_00c5: 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_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			if (Core.CurrentLevelHasInfo && Core.CurrentLevelInfo.Id == 1)
			{
				TextMeshProUGUI component = ((Component)GameObject.Find("/Canvas").transform.Find("HurtScreen").Find("Text 2 Sound").Find("Text (2)")).GetComponent<TextMeshProUGUI>();
				((TMP_Text)component).text = ((TMP_Text)component).text + "\nARCHIPELAGO BY   <color=#fec24c>TRPG</color>";
				((TMP_Text)component).lineSpacing = 25f;
				TextMeshProUGUI component2 = Object.Instantiate<GameObject>(((Component)component).gameObject, ((TMP_Text)component).transform.parent).GetComponent<TextMeshProUGUI>();
				((TMP_Text)component2).text = "and others!";
				((TMP_Text)component2).fontSize = 32f;
				((TMP_Text)component2).transform.localPosition = new Vector3(270f, -70f, 0f);
				((TMP_Text)component2).transform.Rotate(new Vector3(0f, 0f, 6f));
				GameObject val = Object.Instantiate<GameObject>(((Component)component).gameObject, ((TMP_Text)component).transform.parent);
				Object.DestroyImmediate((Object)(object)val.GetComponent<TextMeshProUGUI>());
				Object.DestroyImmediate((Object)(object)val.GetComponent<TMP_SpriteAnimator>());
				Image val2 = val.AddComponent<Image>();
				val2.sprite = UIManager.bundle.LoadAsset<Sprite>("assets/trpg.png");
				((Graphic)val2).color = new Color(0.992f, 0.758f, 0.297f);
				val2.preserveAspect = true;
				((Component)val2).transform.localPosition = new Vector3(150f, -32f, 0f);
				((Component)val2).transform.localScale = new Vector3(0.08f, 0.08f, 0.08f);
				((Component)component).gameObject.AddComponent<LinkedDisabler>().objects.Add(((Component)component2).gameObject);
				((Component)component).gameObject.AddComponent<LinkedDisabler>().objects.Add(((Component)val2).gameObject);
			}
		}

		public static void AddGlassComponents()
		{
			if (!Core.CurrentLevelHasInfo || Core.CurrentLevelInfo.Id != 1)
			{
				return;
			}
			Glass[] array = Resources.FindObjectsOfTypeAll<Glass>();
			foreach (Glass val in array)
			{
				string name = ((Object)((Component)val).transform.parent.parent).name;
				switch (name)
				{
				default:
					if (!(name == "11 Content(Clone)"))
					{
						continue;
					}
					break;
				case "5 Stuff":
				case "5 Stuff(Clone)":
				case "11 Content":
					break;
				}
				GameObject gameObject = ((Component)((Component)val).transform.parent.parent).gameObject;
				if (!Object.op_Implicit((Object)(object)gameObject.GetComponent<GlassDisabler>()))
				{
					gameObject.AddComponent<GlassDisabler>();
				}
			}
		}

		public static void FindHank()
		{
			if (!Core.CurrentLevelHasInfo)
			{
				return;
			}
			HudMessage[] array = Resources.FindObjectsOfTypeAll<HudMessage>();
			foreach (HudMessage val in array)
			{
				if ((Core.CurrentLevelInfo.Id == 9 || Core.CurrentLevelInfo.Id == 22) && ((Object)val).name == "EasterEgg")
				{
					string message = val.message;
					message = message.Replace("Nothing", "Something");
					message = message.Replace("but", "and");
					val.message = message;
					((Component)val).gameObject.AddComponent<Hank>();
				}
			}
		}

		public static void ForceBlueArm()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)MonoSingleton<FistControl>.Instance))
			{
				Core.Logger.LogWarning((object)"FistControl.Instance is null!");
				return;
			}
			MonoSingleton<FistControl>.Instance.forcedLoadout.arm.blueVariant = (VariantOption)1;
			MonoSingleton<FistControl>.Instance.ResetFists();
		}

		public static void FindRocketRaceButton()
		{
			if (!(SceneHelper.CurrentScene != "CreditsMuseum2") && Core.data.rocketReward)
			{
				GameObject.Find("/PuzzleScreen (2)/Canvas/Background/Start").AddComponent<RocketRaceCheck>();
			}
		}
	}
	public class Multiworld : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <Connect>d__30 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Multiworld <>4__this;

			private WeaponLoadout <loadout>5__1;

			private GameProgressMoneyAndGear <gameProgress>5__2;

			private LoginResult <loginResult>5__3;

			private LoginSuccessful <success>5__4;

			private string <totalLocations>5__5;

			private Dictionary<string, int>.KeyCollection.Enumerator <>s__6;

			private string <weapon>5__7;

			private long <locationId>5__8;

			private ScoutedItemInfo <info>5__9;

			private string <itemName>5__10;

			private string <playerName>5__11;

			private HashSet<string>.Enumerator <>s__12;

			private string <loc>5__13;

			private LoginFailure <failure>5__14;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Connect>d__30(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<loadout>5__1 = null;
				<gameProgress>5__2 = null;
				<loginResult>5__3 = null;
				<success>5__4 = null;
				<totalLocations>5__5 = null;
				<>s__6 = default(Dictionary<string, int>.KeyCollection.Enumerator);
				<weapon>5__7 = null;
				<info>5__9 = null;
				<itemName>5__10 = null;
				<playerName>5__11 = null;
				<>s__12 = default(HashSet<string>.Enumerator);
				<loc>5__13 = null;
				<failure>5__14 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Expected O, but got Unknown
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Expected O, but got Unknown
				//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Expected O, but got Unknown
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f9: Expected O, but got Unknown
				//IL_0a75: Unknown result type (might be due to invalid IL or missing references)
				//IL_0ae2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0e8a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0241: Unknown result type (might be due to invalid IL or missing references)
				//IL_024b: Expected O, but got Unknown
				//IL_0ce4: Unknown result type (might be due to invalid IL or missing references)
				//IL_0ce9: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					if (Authenticated)
					{
						return false;
					}
					<loadout>5__1 = WeaponLoadout.Get();
					Core.Logger.LogInfo((object)"Got loadout");
					<gameProgress>5__2 = GameProgressSaver.GetGeneralProgress();
					Core.LockAllWeapons();
					Core.data.unlockedSkulls1_4 = 0;
					Core.data.unlockedSkulls5_1 = 0;
					Session = ArchipelagoSessionFactory.CreateSession(Core.data.host_name, 38281);
					Session.Socket.SocketClosed += new SocketClosedHandler(SocketClosed);
					Session.Socket.ErrorReceived += new ErrorReceivedHandler(ErrorReceived);
					Session.Socket.PacketReceived += new PacketReceivedHandler(PacketReceived);
					Session.Items.ItemReceived += new ItemReceivedHandler(ItemReceived);
					Core.Logger.LogInfo((object)string.Format("Attempting connection ({0} - {1} / {2})", Core.data.slot_name, apVersion, "3.5.0"));
					<loginResult>5__3 = Session.TryConnectAndLogin("ULTRAKILL", Core.data.slot_name, (ItemsHandlingFlags)7, apVersion, (string[])null, (string)null, (Core.data.password == "") ? null : Core.data.password, true);
					ref LoginSuccessful reference = ref <success>5__4;
					LoginResult obj = <loginResult>5__3;
					reference = (LoginSuccessful)(object)((obj is LoginSuccessful) ? obj : null);
					if (<success>5__4 != null)
					{
						Core.Logger.LogInfo((object)"Login successful");
						Authenticated = true;
						PlayerConfig.isConnected.value = true;
						((ConfigField)PlayerConfig.playerName).interactable = false;
						((ConfigField)PlayerConfig.serverAddress).interactable = false;
						((ConfigField)PlayerConfig.serverPassword).interactable = false;
						((ConfigField)PlayerConfig.hintMode).interactable = false;
						((ConfigField)PlayerConfig.chat).interactable = true;
						if (Core.DataExists())
						{
							<>4__this.DoServerCheck(Session, <success>5__4.SlotData);
						}
						else
						{
							AllowConnect = true;
						}
						<>2__current = (object)new WaitUntil((Func<bool>)(() => AllowConnect.HasValue));
						<>1__state = 1;
						return true;
					}
					ref LoginFailure reference2 = ref <failure>5__14;
					LoginResult obj2 = <loginResult>5__3;
					reference2 = (LoginFailure)(object)((obj2 is LoginFailure) ? obj2 : null);
					if (<failure>5__14 != null)
					{
						Core.Logger.LogInfo((object)"Login failed");
						Authenticated = false;
						Core.Logger.LogError((object)string.Join("\n", <failure>5__14.Errors));
						PlayerConfig.connectionInfo.text = string.Join("\n", <failure>5__14.Errors);
						Session.Socket.DisconnectAsync();
						Session = null;
						CanGetItems = false;
						AllowConnect = null;
						((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red;
						Core.SaveGeneralProgress(<gameProgress>5__2);
					}
					<failure>5__14 = null;
					break;
				}
				case 1:
					<>1__state = -1;
					if (!AllowConnect.Value)
					{
						LocationManager.itemQueue.Clear();
						Disconnect();
						return false;
					}
					Core.data.seed = Session.RoomState.Seed;
					TryGetSlotDataValue(ref Core.data.version, <success>5__4.SlotData, "version", string.Empty);
					Core.data.serverVersion = Session.RoomState.GeneratorVersion.ToString();
					Core.Logger.LogInfo((object)string.Format("Server version: {0} / {1}", Session.RoomState.Version, (Core.data.version == string.Empty) ? "?" : Core.data.version));
					TryGetStart(ref Core.data.unlockedLevels, <success>5__4.SlotData, "0-1");
					TryGetGoal(ref Core.data.goal, <success>5__4.SlotData, "6-2");
					TryGetSlotDataValue(ref Core.data.goalRequirement, <success>5__4.SlotData, "goal_requirement", 15);
					TryGetSlotDataValue(ref Core.data.perfectGoal, <success>5__4.SlotData, "perfect_goal", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.secretExitUnlock, <success>5__4.SlotData, "secret_mission_unlock_type", defaultValue: true);
					TryGetSlotDataValue(ref Core.data.secretExitComplete, <success>5__4.SlotData, "secret_exit_behavior", defaultValue: true);
					TryGetEnemyOption(ref Core.data.enemyRewards, <success>5__4.SlotData, "enemy_rewards", EnemyOptions.Disabled);
					TryGetSlotDataValue(ref Core.data.challengeRewards, <success>5__4.SlotData, "challenge_rewards", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.pRankRewards, <success>5__4.SlotData, "p_rank_rewards", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.hankRewards, <success>5__4.SlotData, "hank_rewards", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.clashReward, <success>5__4.SlotData, "randomize_clash_mode", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.fishRewards, <success>5__4.SlotData, "fish_rewards", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.cleanRewards, <success>5__4.SlotData, "cleaning_rewards", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.chessReward, <success>5__4.SlotData, "chess_reward", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.rocketReward, <success>5__4.SlotData, "rocket_race_reward", defaultValue: false);
					TryGetFire2(ref Core.data.randomizeFire2, <success>5__4.SlotData, "randomize_secondary_fire", Fire2Options.Disabled);
					TryGetSlotDataValue(ref Core.data.revForm, <success>5__4.SlotData, "revolver_form", WeaponForm.Standard);
					TryGetSlotDataValue(ref Core.data.shoForm, <success>5__4.SlotData, "shotgun_form", WeaponForm.Standard);
					TryGetSlotDataValue(ref Core.data.naiForm, <success>5__4.SlotData, "nailgun_form", WeaponForm.Standard);
					TryGetSlotDataValue(ref Core.data.randomizeSkulls, <success>5__4.SlotData, "randomize_skulls", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.l1switch, <success>5__4.SlotData, "randomize_limbo_switches", defaultValue: false);
					TryGetSlotDataValue(ref Core.data.l7switch, <success>5__4.SlotData, "randomize_violence_switches", defaultValue: false);
					if (Core.data.randomizeSkulls && !UIManager.createdSkullIcons)
					{
						UIManager.CreateMenuSkullIcons();
					}
					if ((Core.data.l1switch || Core.data.l7switch) && !UIManager.createdSwitchIcons)
					{
						UIManager.CreateMenuSwitchIcons();
					}
					if (!Core.DataExists())
					{
						Core.Logger.LogInfo((object)"Doing first time setup for save file");
						if (Core.data.revForm == WeaponForm.Standard)
						{
							Core.data.revstd = true;
							Core.data.revalt = false;
						}
						else
						{
							Core.data.revstd = false;
							Core.data.revalt = true;
							GameProgressSaver.AddGear("revalt");
						}
						if (Core.data.shoForm == WeaponForm.Standard)
						{
							Core.data.shostd = true;
							Core.data.shoalt = false;
						}
						else
						{
							Core.data.shostd = false;
							Core.data.shoalt = true;
							GameProgressSaver.AddGear("shoalt");
						}
						if (Core.data.naiForm == WeaponForm.Standard)
						{
							Core.data.naistd = true;
							Core.data.naialt = false;
						}
						else
						{
							Core.data.naistd = false;
							Core.data.naialt = true;
							GameProgressSaver.AddGear("naialt");
						}
						TryGetSlotDataValue(ref Core.data.hasArm, <success>5__4.SlotData, "start_with_arm", defaultValue: true);
						TryGetSlotDataValue(ref Core.data.dashes, <success>5__4.SlotData, "starting_stamina", 3);
						TryGetSlotDataValue(ref Core.data.walljumps, <success>5__4.SlotData, "starting_walljumps", 3);
						TryGetSlotDataValue(ref Core.data.canSlide, <success>5__4.SlotData, "start_with_slide", defaultValue: true);
						TryGetSlotDataValue(ref Core.data.canSlam, <success>5__4.SlotData, "start_with_slam", defaultValue: true);
						TryGetSlotDataValue(ref Core.data.multiplier, <success>5__4.SlotData, "point_multiplier", 1);
						TryGetSlotDataValue(ref Core.data.musicRandomizer, <success>5__4.SlotData, "music_randomizer", defaultValue: false);
						if (Core.data.musicRandomizer)
						{
							Core.data.music = JsonConvert.DeserializeObject<Dictionary<string, string>>(<success>5__4.SlotData["music"].ToString());
						}
						TryGetSlotDataValue(ref Core.data.cybergrindHints, <success>5__4.SlotData, "cybergrind_hints", defaultValue: true);
						try
						{
							ColorConfig.uiColorRandomizer.value = (ColorOptions)Enum.Parse(typeof(ColorOptions), <success>5__4.SlotData["ui_color_randomizer"].ToString());
						}
						catch (KeyNotFoundException)
						{
							ColorConfig.uiColorRandomizer.value = ColorOptions.Off;
						}
						try
						{
							ColorConfig.gunColorRandomizer.value = (ColorOptions)Enum.Parse(typeof(ColorOptions), <success>5__4.SlotData["gun_color_randomizer"].ToString());
						}
						catch (KeyNotFoundException)
						{
							ColorConfig.gunColorRandomizer.value = ColorOptions.Off;
						}
						Core.data.playerCount = Session.Players.Players[0].Count - 1;
						MonoSingleton<PrefsManager>.Instance.SetInt("difficulty", 4);
						GameProgressSaver.SetIntro(true);
						GameProgressSaver.SetTutorial(true);
						GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)0);
						GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)1);
						GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)2);
						GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)3);
						GameProgressSaver.UnlockWeaponCustomization((WeaponCustomizationType)4);
						GameProgressSaver.SaveProgress(34);
						GameProgressSaver.SetEncoreProgress(101);
						GameProgressSaver.SetPrime(1, 1);
						GameProgressSaver.SetPrime(2, 1);
						Core.SaveData();
						if (ColorConfig.uiColorRandomizer.value != 0)
						{
							ColorRandomizer.RandomizeUIColors();
						}
						if (ColorConfig.gunColorRandomizer.value != 0)
						{
							ColorRandomizer.RandomizeGunColors();
						}
						Core.data.deathLink = bool.Parse(<success>5__4.SlotData["death_link"].ToString());
						TryGetSlotDataValue(ref Core.data.deathLinkAmnesty, <success>5__4.SlotData, "death_link_amnesty", 1);
					}
					MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 1);
					LocationManager.locations = ((JToken)(JObject)<success>5__4.SlotData["locations"]).ToObject<Dictionary<string, long>>();
					ConfigManager.LoadStats();
					LocationManager.RegenerateItemDefinitions();
					Core.Logger.LogInfo((object)("Successfully connected to server as player \"" + Core.data.slot_name + "\"."));
					PlayerConfig.connectionInfo.text = "Successfully connected to server as player \"" + Core.data.slot_name + "\".";
					((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Green;
					if (Core.data.completedLevels.Count < Core.data.goalRequirement)
					{
						UIManager.CreateGoalCounter();
					}
					<totalLocations>5__5 = ((LocationManager.locations.Count == 0) ? "?" : LocationManager.locations.Count.ToString());
					if (Core.data.deathLink)
					{
						EnableDeathLink();
					}
					else
					{
						DeathLinkConfig.deathLinkStatus.text = "Death Link is <color=red>OFF</color>";
					}
					Core.Logger.LogInfo((object)"Scouting shop items");
					<>s__6 = Core.shopPrices.Keys.GetEnumerator();
					try
					{
						while (<>s__6.MoveNext())
						{
							<weapon>5__7 = <>s__6.Current;
							<locationId>5__8 = LocationManager.locations["shop_" + <weapon>5__7];
							<info>5__9 = Session.Locations.ScoutLocationsAsync(false, new long[1] { LocationManager.locations["shop_" + <weapon>5__7] }).Result[<locationId>5__8];
							<itemName>5__10 = ((ItemInfo)<info>5__9).ItemName;
							<playerName>5__11 = Session.Players.GetPlayerName(PlayerInfo.op_Implicit(<info>5__9.Player));
							if (LocationManager.GetItemDefinition(<itemName>5__10) != null)
							{
								LocationManager.shopScouts.Add("shop_" + <weapon>5__7, new UKItem
								{
									itemName = <itemName>5__10,
									playerName = <playerName>5__11,
									type = LocationManager.GetItemDefinition(<itemName>5__10).Type
								});
							}
							else
							{
								LocationManager.shopScouts.Add("shop_" + <weapon>5__7, new APItem
								{
									itemName = <itemName>5__10,
									playerName = <playerName>5__11,
									type = ((ItemInfo)<info>5__9).Flags
								});
							}
							<info>5__9 = null;
							<itemName>5__10 = null;
							<playerName>5__11 = null;
							<weapon>5__7 = null;
						}
					}
					finally
					{
						((IDisposable)<>s__6).Dispose();
					}
					<>s__6 = default(Dictionary<string, int>.KeyCollection.Enumerator);
					<>s__12 = Core.data.@checked.GetEnumerator();
					try
					{
						while (<>s__12.MoveNext())
						{
							<loc>5__13 = <>s__12.Current;
							LocationManager.CheckLocation(<loc>5__13);
							<loc>5__13 = null;
						}
					}
					finally
					{
						((IDisposable)<>s__12).Dispose();
					}
					<>s__12 = default(HashSet<string>.Enumerator);
					CanGetItems = true;
					((MonoBehaviour)Core.Instance).StartCoroutine("ApplyLoadout", (object)<loadout>5__1);
					<totalLocations>5__5 = null;
					break;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public static Version apVersion = new Version(0, 6, 7);

		public static DeathLinkService DeathLinkService = null;

		public static DeathLink lastDeathLink = null;

		public static int currentDeathCount = 0;

		public static bool Authenticated;

		public static bool HintMode = false;

		public static ArchipelagoSession Session;

		public static List<string> messages = new List<string>();

		public GameObject serverCheckBlocker;

		public TextMeshProUGUI serverCheckText;

		public static List<RecentItem> recentItems = new List<RecentItem>();

		public static bool CanGetItems { get; private set; } = false;


		public static bool? AllowConnect { get; private set; } = null;


		public void SetupServerCheckBlocker()
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Expected O, but got Unknown
			if (!(SceneHelper.CurrentScene != "Main Menu"))
			{
				serverCheckBlocker = ((Component)((Component)Object.Instantiate<GameObject>(((Component)((Component)MonoSingleton<OptionsManager>.Instance.optionsMenu).transform.Find("Save Slots").Find("Reload Consent Blocker")).gameObject, UIManager.canvas.transform).transform.GetChild(0)).transform.parent).gameObject;
				((Object)serverCheckBlocker).name = "Archipelago Server Check Blocker";
				Object.Destroy((Object)(object)serverCheckBlocker.GetComponent<ComponentEvents>());
				Object.Destroy((Object)(object)((Component)serverCheckBlocker.transform.Find("Consent")).GetComponent<Image>());
				((Component)serverCheckBlocker.transform.Find("Consent").Find("Panel")).GetComponent<RectTransform>().sizeDelta = new Vector2(0f, 180f);
				serverCheckText = ((Component)serverCheckBlocker.transform.Find("Consent").Find("Panel").Find("Text")).GetComponent<TextMeshProUGUI>();
				GameObject gameObject = ((Component)serverCheckBlocker.transform.Find("Consent").Find("Panel").Find("Yes")).gameObject;
				((TMP_Text)gameObject.GetComponentInChildren<TextMeshProUGUI>(true)).text = "YES";
				Button component = gameObject.GetComponent<Button>();
				((UnityEventBase)component.onClick).SetPersistentListenerState(0, (UnityEventCallState)0);
				((UnityEventBase)component.onClick).RemoveAllListeners();
				((UnityEvent)component.onClick).AddListener((UnityAction)delegate
				{
					AllowConnect = true;
					serverCheckBlocker.SetActive(false);
				});
				GameObject gameObject2 = ((Component)serverCheckBlocker.transform.Find("Consent").Find("Panel").Find("No")).gameObject;
				((TMP_Text)gameObject2.GetComponentInChildren<TextMeshProUGUI>(true)).text = "NO";
				Button component2 = gameObject2.GetComponent<Button>();
				((UnityEventBase)component2.onClick).SetPersistentListenerState(0, (UnityEventCallState)0);
				((UnityEventBase)component2.onClick).RemoveAllListeners();
				((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
				{
					AllowConnect = false;
					serverCheckBlocker.SetActive(false);
				});
			}
		}

		public void DoServerCheck(ArchipelagoSession session, Dictionary<string, object> slotData)
		{
			if (Core.data.seed != session.RoomState.Seed || Core.data.version != slotData["version"].ToString() || Core.data.serverVersion != session.RoomState.GeneratorVersion.ToString())
			{
				ShowServerCheckBlocker(session, slotData);
			}
			else
			{
				AllowConnect = true;
			}
		}

		public void ShowServerCheckBlocker(ArchipelagoSession session, Dictionary<string, object> slotData)
		{
			if (!((Object)(object)serverCheckBlocker == (Object)null))
			{
				((TMP_Text)serverCheckText).text = "Server does not match saved data.\n\nSaved:\n<size=16>Seed: " + (Utility.IsNullOrWhiteSpace(Core.data.seed) ? "<color=grey>not saved</color>" : Core.data.seed) + "\nWorld Version: " + (Utility.IsNullOrWhiteSpace(Core.data.version) ? "<color=grey>not saved</color>" : Core.data.version) + "\nGenerator Version: " + (Utility.IsNullOrWhiteSpace(Core.data.serverVersion) ? "<color=grey>not saved</color>" : Core.data.serverVersion) + "</size>\n\nServer:\n<size=16>Seed: " + session.RoomState.Seed + string.Format("\nWorld Version: {0}", slotData["version"]) + $"\nGenerator Version: {session.RoomState.GeneratorVersion}</size>" + "\n\nConnect anyway?";
				serverCheckBlocker.SetActive(true);
			}
		}

		public static void TryGetStart(ref HashSet<string> unlockedLevels, Dictionary<string, object> slotData, string defaultValue)
		{
			try
			{
				unlockedLevels.Add(slotData["start"].ToString());
				Core.data.start = slotData["start"].ToString();
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)("No key found for start level. Using default value (" + defaultValue + ")"));
				unlockedLevels.Add(defaultValue);
				Core.data.start = defaultValue;
			}
		}

		public static void TryGetGoal(ref string goal, Dictionary<string, object> slotData, string defaultValue)
		{
			if (int.TryParse(slotData["goal"].ToString(), out var result))
			{
				Core.Logger.LogWarning((object)"Using legacy goal option.");
				switch (result)
				{
				case 0:
					goal = "1-4";
					break;
				case 1:
					goal = "2-4";
					break;
				case 2:
					goal = "3-2";
					break;
				case 3:
					goal = "4-4";
					break;
				case 4:
					goal = "5-4";
					break;
				case 6:
					goal = "P-1";
					break;
				case 7:
					goal = "P-2";
					break;
				case 8:
					goal = "7-4";
					break;
				default:
					goal = "6-2";
					break;
				}
			}
			else
			{
				goal = slotData["goal"].ToString();
			}
		}

		public static void TryGetEnemyOption(ref EnemyOptions option, Dictionary<string, object> slotData, string key, EnemyOptions defaultValue)
		{
			try
			{
				option = (EnemyOptions)int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				try
				{
					option = (EnemyOptions)int.Parse(slotData["boss_rewards"].ToString());
					Core.Logger.LogInfo((object)"Using legacy enemy reward option.");
				}
				catch (KeyNotFoundException)
				{
					Core.Logger.LogWarning((object)$"No key found for enemy rewards. Using default value ({defaultValue})");
					option = defaultValue;
				}
			}
		}

		public static void TryGetFire2(ref Fire2Options option, Dictionary<string, object> slotData, string key, Fire2Options defaultValue)
		{
			if (bool.TryParse(slotData[key].ToString(), out var result))
			{
				Core.Logger.LogInfo((object)"Using legacy secondary fire option.");
				if (result)
				{
					option = Fire2Options.Split;
				}
				else
				{
					option = Fire2Options.Disabled;
				}
				return;
			}
			try
			{
				option = (Fire2Options)int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public static void TryGetSlotDataValue(ref string option, Dictionary<string, object> slotData, string key, string defaultValue)
		{
			try
			{
				option = slotData[key].ToString();
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)("No key found for option \"" + key + "\". Using default value (" + defaultValue + ")"));
				option = defaultValue;
			}
		}

		public static void TryGetSlotDataValue(ref int option, Dictionary<string, object> slotData, string key, int defaultValue)
		{
			try
			{
				option = int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public static void TryGetSlotDataValue(ref bool option, Dictionary<string, object> slotData, string key, bool defaultValue)
		{
			try
			{
				option = bool.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		public static void TryGetSlotDataValue(ref WeaponForm option, Dictionary<string, object> slotData, string key, WeaponForm defaultValue)
		{
			try
			{
				option = (WeaponForm)int.Parse(slotData[key].ToString());
			}
			catch (KeyNotFoundException)
			{
				Core.Logger.LogWarning((object)$"No key found for option \"{key}\". Using default value ({defaultValue})");
				option = defaultValue;
			}
		}

		[IteratorStateMachine(typeof(<Connect>d__30))]
		public IEnumerator Connect()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Connect>d__30(0)
			{
				<>4__this = this
			};
		}

		public static bool ConnectBK()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			if (Authenticated)
			{
				return true;
			}
			Session = ArchipelagoSessionFactory.CreateSession(Core.data.host_name, 38281);
			Session.Socket.SocketClosed += new SocketClosedHandler(SocketClosed);
			Session.Socket.ErrorReceived += new ErrorReceivedHandler(ErrorReceived);
			Session.Socket.PacketReceived += new PacketReceivedHandler(PacketReceived);
			LoginResult val = Session.TryConnectAndLogin("", Core.data.slot_name, (ItemsHandlingFlags)0, apVersion, new string[1] { "HintGame" }, (string)null, (Core.data.password == "") ? null : Core.data.password, false);
			LoginSuccessful val2 = (LoginSuccessful)(object)((val is LoginSuccessful) ? val : null);
			if (val2 != null)
			{
				Authenticated = true;
				HintMode = true;
				PlayerConfig.isConnected.value = true;
				((ConfigField)PlayerConfig.playerName).interactable = false;
				((ConfigField)PlayerConfig.serverAddress).interactable = false;
				((ConfigField)PlayerConfig.serverPassword).interactable = false;
				((ConfigField)PlayerConfig.hintMode).interactable = false;
				((ConfigField)PlayerConfig.chat).interactable = true;
				Core.Logger.LogInfo((object)("Successfully connected to server in hint mode as player \"" + Core.data.slot_name + "\"."));
				PlayerConfig.connectionInfo.text = "Successfully connected to server in hint mode as player \"" + Core.data.slot_name + "\".";
				((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Green;
			}
			else
			{
				LoginFailure val3 = (LoginFailure)(object)((val is LoginFailure) ? val : null);
				if (val3 != null)
				{
					Authenticated = false;
					HintMode = false;
					Core.Logger.LogError((object)string.Join("\n", val3.Errors));
					PlayerConfig.connectionInfo.text = string.Join("\n", val3.Errors);
					Session.Socket.DisconnectAsync();
					Session = null;
					((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red;
				}
			}
			return val.Successful;
		}

		public static void Disconnect()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			PlayerConfig.isConnected.value = false;
			((ConfigField)PlayerConfig.playerName).interactable = true;
			((ConfigField)PlayerConfig.serverAddress).interactable = true;
			((ConfigField)PlayerConfig.serverPassword).interactable = true;
			((ConfigField)PlayerConfig.hintMode).interactable = true;
			((ConfigField)PlayerConfig.chat).interactable = false;
			if (Session != null && Session.Socket != null)
			{
				Session.Socket.DisconnectAsync();
			}
			if (SceneHelper.CurrentScene == "Main Menu")
			{
				((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red;
			}
			UIManager.SetLogText("");
			messages.Clear();
			LocationManager.shopScouts = new Dictionary<string, AItem>();
			Session = null;
			DeathLinkService = null;
			Authenticated = false;
			HintMode = false;
			CanGetItems = false;
			AllowConnect = null;
		}

		public static void SocketClosed(string reason)
		{
			Core.Logger.LogError((object)("Lost connection to Archipelago server. " + reason));
			Disconnect();
		}

		public static void ErrorReceived(Exception e, string message)
		{
			Core.Logger.LogError((object)message);
			if (e != null)
			{
				Core.Logger.LogError((object)e.ToString());
			}
			Disconnect();
		}

		public static void PacketReceived(ArchipelagoPacketBase packet)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_0053: 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_0080: Invalid comparison between Unknown and I4
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Invalid comparison between Unknown and I4
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0576: Unknown result type (might be due to invalid IL or missing references)
			//IL_057b: Unknown result type (might be due to invalid IL or missing references)
			//IL_057d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0580: Unknown result type (might be due to invalid IL or missing references)
			//IL_059a: Expected I4, but got Unknown
			//IL_07ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0724: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c6: Expected I4, but got Unknown
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0707: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Unknown result type (might be due to invalid IL or missing references)
			//IL_0485: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_050e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			ArchipelagoPacketType packetType = packet.PacketType;
			ArchipelagoPacketType val = packetType;
			if ((int)val != 6)
			{
				return;
			}
			if (messages.Count >= UIManager.lines)
			{
				messages.RemoveAt(0);
			}
			PrintJsonPacket val2 = (PrintJsonPacket)(object)((packet is PrintJsonPacket) ? packet : null);
			string text = "";
			string text2 = "";
			string text3 = "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.White) + "FF>";
			if ((int)val2.Data[0].Type.GetValueOrDefault() == 1 && Session.Players.GetPlayerName(int.Parse(val2.Data[0].Text)) == Core.data.slot_name && val2.Data[1].Text == " found their ")
			{
				string locationNameFromId = Session.Locations.GetLocationNameFromId(long.Parse(val2.Data[4].Text), (string)null);
				string itemName = Session.Items.GetItemName(long.Parse(val2.Data[2].Text), (string)null);
				ItemFlags value = val2.Data[2].Flags.Value;
				string text4 = "";
				string locationColor = null;
				if (locationNameFromId.StartsWith("Enemy:") || locationNameFromId.StartsWith("Boss:"))
				{
					text4 = LocationManager.GetCurrentLevelImage();
					locationColor = Core.CurrentLevelInfo?.Name;
				}
				else
				{
					text4 = LocationManager.GetLocationImage(locationNameFromId);
				}
				Core.data.recentLocations.Add(new RecentLocation(locationNameFromId, text4, locationColor, itemName, value, Core.data.slot_name));
				if (Core.data.recentLocations.Count > 5)
				{
					Core.data.recentLocations.RemoveAt(0);
				}
			}
			else if ((int)val2.Data[0].Type.GetValueOrDefault() == 1 && Session.Players.GetPlayerName(int.Parse(val2.Data[0].Text)) == Core.data.slot_name && val2.Data[1].Text == " sent ")
			{
				string itemName2 = Session.Items.GetItemName(long.Parse(val2.Data[2].Text), Session.Players.GetPlayerInfo(val2.Data[2].Player.Value).Game);
				ItemFlags value2 = val2.Data[2].Flags.Value;
				string playerAlias = Session.Players.GetPlayerAlias(int.Parse(val2.Data[4].Text));
				string locationNameFromId2 = Session.Locations.GetLocationNameFromId(long.Parse(val2.Data[6].Text), (string)null);
				string text5 = "";
				string locationColor2 = null;
				if (locationNameFromId2.StartsWith("Enemy:") || locationNameFromId2.StartsWith("Boss:"))
				{
					text5 = LocationManager.GetCurrentLevelImage();
					locationColor2 = Core.CurrentLevelInfo?.Name;
				}
				else
				{
					text5 = LocationManager.GetLocationImage(locationNameFromId2);
				}
				Core.data.recentLocations.Add(new RecentLocation(locationNameFromId2, text5, locationColor2, itemName2, value2, playerAlias));
				if (Core.data.recentLocations.Count > 5)
				{
					Core.data.recentLocations.RemoveAt(0);
				}
				Color white = Color.white;
				if (LocationManager.GetItemDefinition(itemName2) != null)
				{
					white = LocationManager.GetItemDefinition(itemName2).Color();
					LocationManager.messages.Add(new Message
					{
						image = LocationManager.GetItemDefinition(itemName2).Image,
						color = Colors.Gray,
						message = "FOUND: <color=#" + ColorUtility.ToHtmlStringRGBA(white) + ">" + itemName2.ToUpper() + "</color> (<color=#" + ColorUtility.ToHtmlStringRGBA(Colors.PlayerOther) + ">" + playerAlias + "</color>)"
					});
				}
				else
				{
					white = LocationManager.GetAPMessageColor(val2.Data[2].Flags.Value);
					LocationManager.messages.Add(new Message
					{
						image = LocationManager.GetAPImage(val2.Data[2].Flags.Value),
						color = LocationManager.GetAPMessageColor(val2.Data[2].Flags.Value),
						message = "FOUND: <color=#" + ColorUtility.ToHtmlStringRGBA(white) + ">" + itemName2.ToUpper() + "</color> (<color=#" + ColorUtility.ToHtmlStringRGBA(Colors.PlayerOther) + ">" + playerAlias + "</color>)"
					});
				}
			}
			JsonMessagePart[] data = val2.Data;
			foreach (JsonMessagePart val3 in data)
			{
				switch (val3.Type)
				{
				case 0L:
				{
					text3 = ((!(Session.Players.GetPlayerName(int.Parse(val3.Text)) == Core.data.slot_name)) ? ("<color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerOther) + "FF>") : ("<color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerSelf) + "FF>"));
					if (int.TryParse(val3.Text, out var result3))
					{
						string text8 = Session.Players.GetPlayerAlias(result3) ?? $"Slot: {result3}";
						text = text + text3 + text8 + "</color>";
						text2 += text8;
					}
					else
					{
						text = text + text3 + val3.Text + "</color>";
						text2 += val3.Text;
					}
					break;
				}
				case 2L:
				{
					text3 = val3.Flags switch
					{
						0L => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemAdvancement) + "FF>", 
						1L => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemNeverExclude) + "FF>", 
						3L => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemTrap) + "FF>", 
						_ => "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemFiller) + "FF>", 
					};
					if (long.TryParse(val3.Text, out var result2))
					{
						string text7 = Session.Items.GetItemName(result2, Session.Players.GetPlayerInfo(val3.Player.Value).Game) ?? $"Item: {result2}";
						text = text + text3 + text7 + "</color>";
						text2 += text7;
					}
					else
					{
						text = text + text3 + val3.Text + "</color>";
						text2 += val3.Text;
					}
					break;
				}
				case 4L:
				{
					text3 = "<color=#" + ColorUtility.ToHtmlStringRGB(Colors.Location) + "FF>";
					if (long.TryParse(val3.Text, out var result))
					{
						string text6 = Session.Locations.GetLocationNameFromId(result, Session.Players.GetPlayerInfo(val3.Player.Value).Game) ?? $"Location: {result}";
						text = text + text3 + text6 + "</color>";
						text2 += text6;
					}
					else
					{
						text = text + text3 + val3.Text + "</color>";
						text2 += val3.Text;
					}
					break;
				}
				default:
					text += val3.Text;
					text2 += val3.Text;
					break;
				}
			}
			messages.Add(text);
			UIManager.SetLogText(string.Join("\n", messages.ToArray()));
		}

		public static void ItemReceived(ReceivedItemsHelper helper)
		{
			bool flag = LocationManager.ShouldGetItemAgain(LocationManager.GetItemDefinition(helper.PeekItem().ItemName).Type);
			bool silent = helper.Index <= Core.data.index && flag;
			if (helper.Index > Core.data.index || flag)
			{
				ItemInfo val = helper.PeekItem();
				string itemName = val.ItemName;
				string playerName = Session.Players.GetPlayerName(PlayerInfo.op_Implicit(val.Player));
				playerName = ((!(playerName == Core.data.slot_name)) ? ((Session.Players.GetPlayerAlias(PlayerInfo.op_Implicit(val.Player)) == "") ? "?" : Session.Players.GetPlayerAlias(PlayerInfo.op_Implicit(val.Player))) : null);
				if (helper.Index > Core.data.index)
				{
					Core.Logger.LogInfo((object)("Name: \"" + itemName + "\" | Type: " + LocationManager.GetItemDefinition(itemName).Type.ToString() + " | Player: \"" + playerName + "\""));
				}
				UKType type = LocationManager.GetItemDefinition(itemName).Type;
				UKItem item = new UKItem
				{
					itemName = itemName,
					type = type,
					playerName = Core.data.slot_name
				};
				LocationManager.itemQueue.Add(new QueuedItem(item, playerName, silent));
				recentItems.Add(new RecentItem(itemName, playerName, helper.Index));
				if (recentItems.Count > 5)
				{
					recentItems.RemoveAt(0);
				}
				if (helper.Index > Core.data.index)
				{
					Core.data.index++;
				}
			}
			helper.DequeueItem();
		}

		public static void EnableDeathLink()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if (DeathLinkService == null)
			{
				DeathLinkService = DeathLinkProvider.CreateDeathLinkService(Session);
				DeathLinkService.OnDeathLinkReceived += new DeathLinkReceivedHandler(DeathLinkReceived);
			}
			DeathLinkService.EnableDeathLink();
			Core.data.deathLink = true;
			DeathLinkConfig.deathLinkStatus.text = "Death Link is <color=green>ON</color>";
			DeathLinkConfig.UpdateDeathLinkCount();
			if (Core.IsInLevel && (Object)(object)Core.uim.deathLinkMessage == (Object)null)
			{
				Core.uim.CreateDeathLinkMessage();
			}
		}

		public static void DisableDeathLink()
		{
			if (DeathLinkService != null)
			{
				DeathLinkService.DisableDeathLink();
				Core.data.deathLink = false;
				DeathLinkConfig.deathLinkStatus.text = "Death Link is <color=red>OFF</color>";
				DeathLinkConfig.deathLinkCount.text = "";
			}
		}

		public static void DeathLinkReceived(DeathLink deathLink)
		{
			if (Core.IsInLevel)
			{
				lastDeathLink = deathLink;
			}
			else
			{
				Core.Logger.LogWarning((object)"Received DeathLink, but player cannot be killed right now.");
			}
		}

		public static void SendCompletion()
		{
			Core.Logger.LogInfo((object)"Goal completed!");
			ArchipelagoSession session = Session;
			if (session != null)
			{
				session.SetGoalAchieved();
			}
		}

		public static void UpdateCompletedLevels()
		{
			if (Session != null)
			{
				Session.DataStorage[(Scope)3, "completedLevels"] = DataStorageElement.op_Implicit((Array)Core.data.completedLevels.ToArray());
			}
		}

		public static bool ServerVersionIsAtLeast(string version)
		{
			if (Utility.IsNullOrWhiteSpace(Core.data.version) || Core.data.version == "?")
			{
				return false;
			}
			if (Core.data.version == version)
			{
				return true;
			}
			if (Core.data.version.CompareTo(version) < 0)
			{
				return false;
			}
			return true;
		}
	}
	public static class LocationManager
	{
		public static GameProgressMoneyAndGear generalProgress;

		public static Dictionary<string, long> locations = new Dictionary<string, long>();

		public static Dictionary<string, AItem> shopScouts = new Dictionary<string, AItem>();

		public static List<Message> messages = new List<Message>();

		public static List<Powerup> powerupQueue = new List<Powerup>();

		public static int soapWaiting = 0;

		public static List<QueuedItem> itemQueue = new List<QueuedItem>();

		public static readonly List<string> fire2Weapons = new List<string>
		{
			"Revolver - Piercer", "Revolver - Marksman", "Revolver - Sharpshooter", "Shotgun - Core Eject", "Shotgun - Pump Charge", "Shotgun - Sawed-On", "Nailgun - Attractor", "Nailgun - Overheat", "Nailgun - JumpStart", "Rocket Launcher - Freezeframe",
			"Rocket Launcher - S.R.S. Cannon", "Rocket Launcher - Firestarter"
		};

		public static List<ItemDefinition> ItemDefinitions { get; private set; }

		public static void RegenerateItemDefinitions()
		{
			ItemDefinitions = new List<ItemDefinition>
			{
				new ItemDefinition("Revolver - Piercer", UKType.Weapon, () => Colors.VariationBlue, (Core.data.revForm == WeaponForm.Standard) ? "rev" : "revalt"),
				new ItemDefinition("Revolver - Marksman", UKType.Weapon, () => Colors.VariationGreen, (Core.data.revForm == WeaponForm.Standard) ? "rev" : "revalt"),
				new ItemDefinition("Revolver - Sharpshooter", UKType.Weapon, () => Colors.VariationRed, (Core.data.revForm == WeaponForm.Standard) ? "rev" : "revalt"),
				new ItemDefinition("Revolver - Standard", UKType.WeaponAlt, () => Colors.WeaponAlt, "rev"),
				new ItemDefinition("Revolver - Alternate", UKType.WeaponAlt, () => Colors.WeaponAlt, "revalt"),
				new ItemDefinition("Shotgun - Core Eject", UKType.Weapon, () => Colors.VariationBlue, (Core.data.shoForm == WeaponForm.Standard) ? "sho" : "shoalt"),
				new ItemDefinition("Shotgun - Pump Charge", UKType.Weapon, () => Colors.VariationGreen, (Core.data.shoForm == WeaponForm.Standard) ? "sho" : "shoalt"),
				new ItemDefinition("Shotgun - Sawed-On", UKType.Weapon, () => Colors.VariationRed, (Core.data.shoForm == WeaponForm.Standard) ? "sho" : "shoalt"),
				new ItemDefinition("Shotgun - Standard", UKType.WeaponAlt, () => Colors.WeaponAlt, "sho"),
				new ItemDefinition("Shotgun - Alternate", UKType.WeaponAlt, () => Colors.WeaponAlt, "shoalt"),
				new ItemDefinition("Nailgun - Attractor", UKType.Weapon, () => Colors.VariationBlue, (Core.data.naiForm == WeaponForm.Standard) ? "nai" : "naialt"),
				new ItemDefinition("Nailgun - Overheat", UKType.Weapon, () => Colors.VariationGreen, (Core.data.naiForm == WeaponForm.Standard) ? "nai" : "naialt"),
				new ItemDefinition("Nailgun - JumpStart", UKType.Weapon, () => Colors.VariationRed, (Core.data.naiForm == WeaponForm.Standard) ? "nai" : "naialt"),
				new ItemDefinition("Nailgun - Standard", UKType.WeaponAlt, () => Colors.WeaponAlt, "nai"),
				new ItemDefinition("Nailgun - Alternate", UKType.WeaponAlt, () => Colors.WeaponAlt, "naialt"),
				new ItemDefinition("Railcannon - Electric", UKType.Weapon, () => Colors.VariationBlue, "rai"),
				new ItemDefinition("Railcannon - Screwdriver", UKType.Weapon, () => Colors.VariationGreen, "rai"),
				new ItemDefinition("Railcannon - Malicious", UKType.Weapon, () => Colors.VariationRed, "rai"),
				new ItemDefinition("Rocket Launcher - Freezeframe", UKType.Weapon, () => Colors.VariationBlue, "rock"),
				new ItemDefinition("Rocket Launcher - S.R.S. Cannon", UKType.Weapon, () => Colors.VariationGreen, "rock"),
				new ItemDefinition("Rocket Launcher - Firestarter", UKType.Weapon, () => Colors.VariationRed, "rock"),
				new ItemDefinition("Secondary Fire - Piercer", UKType.Fire2, () => Colors.VariationBlue, "rev0_fire2"),
				new ItemDefinition("Secondary Fire - Marksman", UKType.Fire2, () => Colors.VariationGreen, "rev2_fire2"),
				new ItemDefinition("Secondary Fire - Sharpshooter", UKType.Fire2, () => Colors.VariationRed, "rev1_fire2"),
				new ItemDefinition("Secondary Fire - Core Eject", UKType.Fire2, () => Colors.VariationBlue, "sho0_fire2"),
				new ItemDefinition("Secondary Fire - Pump Charge", UKType.Fire2, () => Colors.VariationGreen, "sho1_fire2"),
				new ItemDefinition("Secondary Fire - Sawed-On", UKType.Fire2, () => Colors.VariationRed, "sho2_fire2"),
				new ItemDefinition("Secondary Fire - Attractor", UKType.Fire2, () => Colors.VariationBlue, "nai0_fire2"),
				new ItemDefinition("Secondary Fire - Overheat", UKType.Fire2, () => Colors.VariationGreen, (Core.data.naiForm == WeaponForm.Standard) ? "naistd1_fire2" : "naialt1_fire2"),
				new ItemDefinition("Secondary Fire - JumpStart", UKType.Fire2, () => Colors.VariationRed, "nai2_fire2"),
				new ItemDefinition("Secondary Fire - Freezeframe", UKType.Fire2, () => Colors.VariationBlue, "rock0_fire2"),
				new ItemDefinition("Secondary Fire - S.R.S. Cannon", UKType.Fire2, () => Colors.VariationGreen, "rock1_fire2"),
				new ItemDefinition("Secondary Fire - Firestarter", UKType.Fire2, () => Colors.VariationRed, "rock2_fire2"),
				new ItemDefinition("Feedbacker", UKType.Arm, () => Colors.VariationBlue, "arm0"),
				new ItemDefinition("Knuckleblaster", UKType.Arm, () => Colors.VariationRed, "arm1"),
				new ItemDefinition("Whiplash", UKType.Arm, () => Colors.VariationGreen, "arm2"),
				new ItemDefinition("Stamina Bar", UKType.Ability, () => Colors.Stamina, "dash"),
				new ItemDefinition("Wall Jump", UKType.Ability, () => Colors.Stamina, "walljump"),
				new ItemDefinition("Slide", UKType.Ability, () => Colors.Stamina, "slide"),
				new ItemDefinition("Slam", UKType.Ability, () => Colors.Stamina, "slam"),
				new ItemDefinition("Blue Skull (0-2)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (0-S)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (0-S)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Red Skull (1-1)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (1-1)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (1-2)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (1-2)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (1-3)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (1-3)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (1-4)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (2-3)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (2-3)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (2-4)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (2-4)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (4-2)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (4-2)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (4-3)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (4-4)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (5-1)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (5-2)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (5-2)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (5-3)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (5-3)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Red Skull (6-1)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Red Skull (7-1)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (7-1)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (7-2)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Red Skull (7-S)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (7-S)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (8-1)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (8-1)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (8-2)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (8-2)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Red Skull (8-3)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (8-3)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (8-4)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (8-4)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (0-E)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Red Skull (0-E)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Red Skull (1-E)", UKType.Skull, () => Colors.RedSkull, "skullr"),
				new ItemDefinition("Blue Skull (1-E)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("Blue Skull (P-2)", UKType.Skull, () => Colors.BlueSkull, "skullb"),
				new ItemDefinition("0-1: INTO THE FIRE", UKType.Level, () => Colors.Layer0, "layer0"),
				new ItemDefinition("0-2: THE MEATGRINDER", UKType.Level, () => Colors.Layer0, "layer0"),
				new ItemDefinition("0-3: DOUBLE DOWN", UKType.Level, () => Colors.Layer0, "layer0"),
				new ItemDefinition("0-4: A ONE-MACHINE ARMY", UKType.Level, () => Colors.Layer0, "layer0"),
				new ItemDefinition("0-5: CERBERUS", UKType.Level, () => Colors.Layer0, "layer0"),
				new ItemDefinition("0-S: SOMETHING WICKED", UKType.SecretMission, () => Colors.Layer0, "layer0"),
				new ItemDefinition("1-1: HEART OF THE SUNRISE", UKType.Level, () => Colors.Layer1, "layer1"),
				new ItemDefinition("1-2: THE BURNING WORLD", UKType.Level, () => Colors.Layer1, "layer1"),
				new ItemDefinition("1-3: HALLS OF SACRED REMAINS", UKType.Level, () => Colors.Layer1, "layer1"),
				new ItemDefinition("1-4: CLAIR DE LUNE", UKType.Level, () => Colors.Layer1, "layer1"),
				new ItemDefinition("1-S: THE WITLESS", UKType.SecretMission, () => Colors.Layer1, "layer1"),
				new ItemDefinition("2-1: BRIDGEBURNER", UKType.Level, () => Colors.Layer2, "layer2"),
				new ItemDefinition("2-2: DEATH AT 20,000 VOLTS", UKType.Level, () => Colors.Layer2, "layer2"),
				new ItemDefinition("2-3: SHEER HEART ATTACK", UKType.Level, () => Colors.Layer2, "layer2"),
				new ItemDefinition("2-4: COURT OF THE CORPSE KING", UKType.Level, () => Colors.Layer2, "layer2"),
				new ItemDefinition("2-S: ALL IMPERFECT LOVE SONG", UKType.SecretMission, () => Colors.Layer2, "layer2"),
				new ItemDefinition("3-1: BELLY OF THE BEAST", UKType.Level, () => Colors.Layer3, "layer3"),
				new ItemDefinition("3-2: IN THE FLESH", UKType.Level, () => Colors.Layer3, "layer3"),
				new ItemDefinition("4-1: SLAVES TO POWER", UKType.Level, () => Colors.Layer4, "layer4"),
				new ItemDefinition("4-2: GOD DAMN THE SUN", UKType.Level, () => Colors.Layer4, "layer4"),
				new ItemDefinition("4-3: A SHOT IN THE DARK", UKType.Level, () => Colors.Layer4, "layer4"),
				new ItemDefinition("4-4: CLAIR DE SOLEIL", UKType.Level, () => Colors.Layer4, "layer4"),
				new ItemDefinition("4-S: CLASH OF THE BRANDICOOT", UKType.SecretMission, () => Colors.Layer4, "layer4"),
				new ItemDefinition("5-1: IN THE WAKE OF POSEIDON", UKType.Level, () => Colors.Layer5, "layer5"),
				new ItemDefinition("5-2: WAVES OF THE STARLESS SEA", UKType.Level, () => Colors.Layer5, "layer5"),
				new ItemDefinition("5-3: SHIP OF FOOLS", UKType.Level, () => Colors.Layer5, "layer5"),
				new ItemDefinition("5-4: LEVIATHAN", UKType.Level, () => Colors.Layer5, "layer5"),
				new ItemDefinition("5-S: I ONLY SAY MORNING", UKType.SecretMission, () => Colors.Layer5, "layer5"),
				new ItemDefinition("6-1: CRY FOR THE WEEPER", UKType.Level, () => Colors.Layer6, "layer6"),
				new ItemDefinition("6-2: AESTHETICS OF HATE", UKType.Level, () => Colors.Layer6, "layer6"),
				new ItemDefinition("7-1: GARDEN OF FORKING PATHS", UKType.Level, () => Colors.Layer7, "layer7"),
				new ItemDefinition("7-2: LIGHT UP THE NIGHT", UKType.Level, () => Colors.Layer7, "layer7"),
				new ItemDefinition("7-3: NO SOUND, NO MEMORY", UKType.Level, () => Colors.Layer7, "layer7"),
				new ItemDefinition("7-4: ...LIKE ANTENNAS TO HEAVEN", UKType.Level, () => Colors.Layer7, "layer7"),
				new ItemDefinition("7-S: HELL BATH NO FURY", UKType.SecretMission, () => Colors.Layer7, "layer7"),
				new ItemDefinition("8-1: HURTBREAK WONDERLAND", UKType.Level, () => Colors.Layer8, "layer8"),
				new ItemDefinition("8-2: THROUGH THE MIRROR", UKType.Level, () => Colors.Layer8, "layer8"),
				new ItemDefinition("8-3: DISINTEGRATION LOOP", UKType.Level, () => Colors.Layer8, "layer8"),
				new ItemDefinition("8-4: FINAL FLIGHT", UKType.Level, () => Colors.Layer8, "layer8"),
				new ItemDefinition("0-E: THIS HEAT, AN EVIL HEAT", UKType.Level, () => Colors.Encore0, "layer0"),
				new ItemDefinition("1-E: ...THEN FELL THE ASHES", UKType.Level, () => Colors.Encore1, "layer1"),
				new ItemDefinition("P-1: SOUL SURVIVOR", UKType.Level, () => Colors.Prime, "layer3"),
				new ItemDefinition("P-2: WAIT OF THE WORLD", UKType.Level, () => Colors.Prime, "layer6"),
				new ItemDefinition("OVERTURE: THE MOUTH OF HELL", UKType.Layer, () => Colors.Layer0, "layer0"),
				new ItemDefinition("LAYER 1: LIMBO", UKType.Layer, () => Colors.Layer1, "layer1"),
				new ItemDefinition("LAYER 2: LUST", UKType.Layer, () => Colors.Layer2, "layer2"),
				new ItemDefinition("LAYER 3: GLUTTONY", UKType.Layer, () => Colors.Layer3, "layer3"),
				new ItemDefinition("LAYER 4: GREED", UKType.Layer, () => Colors.Layer4, "layer4"),
				new ItemDefinition("LAYER 5: WRATH", UKType.Layer, () => Colors.Layer5, "layer5"),
				new ItemDefinition("LAYER 6: HERESY", UKType.Layer, () => Colors.Layer6, "layer6"),
				new ItemDefinition("LAYER 7: VIOLENCE", UKType.Layer, () => Colors.Layer7, "layer7"),
				new ItemDefinition("LAYER 8: FRAUD", UKType.Layer, () => Colors.Layer8, "layer8"),
				new ItemDefinition("+10,000P", UKType.Points, () => Colors.Points, "points"),
				new ItemDefinition("Overheal", UKType.Powerup, () => Colors.Overheal, "overheal"),
				new ItemDefinition("Dual Wield", UKType.Powerup, () => Colors.DualWield, "dualwield"),
				new ItemDefinition("Infinite Stamina", UKType.Powerup, () => Colors.Stamina, "infinitestamina"),
				new ItemDefinition("Air Jump", UKType.Powerup, () => Colors.DoubleJump, "doublejump"),
				new ItemDefinition("Soap", UKType.Soap, () => Colors.White, "soap"),
				new ItemDefinition("Confusing Aura", UKType.Powerup, () => Colors.Confusion, "confusion"),
				new ItemDefinition("Quick Charge", UKType.Powerup, () => Colors.VariationBlue, "quickcharge"),
				new ItemDefinition("Hard Damage", UKType.Trap, () => Colors.Trap, "overheal"),
				new ItemDefinition("Stamina Limiter", UKType.Trap, () => Colors.Trap, "infinitestamina"),
				new ItemDefinition("Wall Jump Limiter", UKType.Trap, () => Colors.Trap, "walljumptrap"),
				new ItemDefinition("Weapon Malfunction", UKType.Trap, () => Colors.Trap, "quickcharge"),
				new ItemDefinition("Empty Ammunition", UKType.Trap, () => Colors.Trap, "quickcharge"),
				new ItemDefinition("Radiant Aura", UKType.Trap, () => Colors.Trap, "radiance"),
				new ItemDefinition("Hands-Free Mode", UKType.Trap, () => Colors.Trap, "noarms"),
				new ItemDefinition("Short-Term Sandstorm", UKType.Trap, () => Colors.Trap, "sandstorm"),
				new ItemDefinition("Limbo Switch I", UKType.LimboSwitch, () => Colors.Switch, "switch1"),
				new ItemDefinition("Limbo Switch II", UKType.LimboSwitch, () => Colors.Switch, "switch2"),
				new ItemDefinition("Limbo Switch III", UKType.LimboSwitch, () => Colors.Switch, "switch3"),
				new ItemDefinition("Limbo Switch IV", UKType.LimboSwitch, () => Colors.Switch, "switch4"),
				new ItemDefinition("Violence Switch I", UKType.ShotgunSwitch, () => Colors.Switch, "switch1"),
				new ItemDefinition("Violence Switch II", UKType.ShotgunSwitch, () => Colors.Switch, "switch2"),
				new ItemDefinition("Violence Switch III", UKType.ShotgunSwitch, () => Colors.Switch, "switch3"),
				new ItemDefinition("Clash Mode", UKType.ClashMode, () => Colors.Layer4, "clash")
			};
		}

		public static ItemDefinition GetItemDefinition(string name)
		{
			foreach (ItemDefinition itemDefinition in ItemDefinitions)
			{
				if (itemDefinition.Name == name)
				{
					return itemDefinition;
				}
			}
			return null;
		}

		public static void CheckLocation(string loc)
		{
			bool flag = MonoSingleton<AssistController>.Instance.cheatsEnabled;
			if (SceneHelper.CurrentScene == "CreditsMuseum2")
			{
				flag = false;
			}
			if (!flag)
			{
				if (!Core.data.@checked.Contains(loc))
				{
					Core.data.@checked.Add(loc);
				}
				if (locations.ContainsKey(loc) && Multiworld.Authenticated)
				{
					if (SceneHelper.CurrentScene != "Level 7-S")
					{
						Core.Logger.LogInfo((object)$"Checking location \"{loc}\" | {locations[loc]}");
					}
					Multiworld.Session.Locations.CompleteLocationChecks(new long[1] { locations[loc] });
				}
				else
				{
					Core.Logger.LogWarning((object)("Location \"" + loc + "\" does not exist."));
				}
			}
			else
			{
				if (Object.op_Implicit((Object)(object)MonoSingleton<HudMessageReceiver>.Instance))
				{
					MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Skipping location check because cheats are enabled!", "", "", 0, false, false, true);
				}
				Core.Logger.LogWarning((object)("Skipping location check \"" + loc + "\" because cheats are enabled!"));
			}
		}

		public static bool ShouldGetItemAgain(UKType type)
		{
			List<UKType> list = new List<UKType>
			{
				UKType.Weapon,
				UKType.WeaponAlt,
				UKType.Arm,
				UKType.Skull,
				UKType.Level,
				UKType.Layer,
				UKType.Fire2,
				UKType.LimboSwitch,
				UKType.ShotgunSwitch,
				UKType.ClashMode,
				UKType.SecretMission
			};
			if (list.Contains(type))
			{
				return true;
			}
			return false;
		}

		public static void GetUKItem(UKItem item, string sendingPlayer = null, bool silent = false, bool save = true)
		{
			//IL_0011: 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_11ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_11b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_110d: Unknown result type (might be due to invalid IL or missing references)
			//IL_1112: Unknown result type (might be due to invalid IL or missing references)
			string text = ColorUtility.ToHtmlStringRGB(GetItemDefinition(item.itemName).Color());
			string text2 = ColorUtility.ToHtmlStringRGB(Colors.PlayerOther);
			string text3 = "";
			if (item.playerName == Core.data.slot_name)
			{
				if (item.type == UKType.Weapon && Core.data.randomizeFire2 == Fire2Options.Progressive && fire2Weapons.Contains(item.itemName))
				{
					FieldInfo field = typeof(GameProgressMoneyAndGear).GetField(GetWeaponIdFromName(item.itemName), BindingFlags.Instance | BindingFlags.Public);
					if ((int)field.GetValue(generalProgress) > 0)
					{
						item.itemName = "Secondary Fire -" + item.itemName.Split(new char[1] { '-' }, 2)[1];
						item.type = UKType.Fire2;
					}
				}
				switch (item.type)
				{
				case UKType.Weapon:
				{
					string weaponIdFromName2 = GetWeaponIdFromName(item.itemName);
					int num = 1;
					if ((weaponIdFromName2.Contains("rev") && Core.data.revForm == WeaponForm.Alternate) || (weaponIdFromName2.Contains("sho") && Core.data.shoForm == WeaponForm.Alternate) || (weaponIdFromName2.Contains("nai") && Core.data.naiForm == WeaponForm.Alternate))
					{
						num = 2;
					}
					GameProgressSaver.AddGear(weaponIdFromName2);
					MonoSingleton<PrefsManager>.Instance.SetInt("weapon." + weaponIdFromName2, num);
					if (Core.CanGetWeapon)
					{
						MonoSingleton<GunSetter>.Instance.ResetWeapons(false);
						MonoSingleton<GunSetter>.Instance.ForceWeapon(weaponIdFromName2);
						if (MonoSingleton<FistControl>.Instance.shopping)
						{
							MonoSingleton<GunControl>.Instance.NoWeapon();
						}
					}
					text3 = "WEAPON: ";
					generalProgress = GameProgressSaver.GetGeneralProgress();
					break;
				}
				case UKType.WeaponAlt:
				{
					string weaponIdFromName = GetWeaponIdFromName(item.itemName);
					switch (weaponIdFromName)
					{
					case "revalt":
						if (Core.data.revForm == WeaponForm.Standard)
						{
							Core.data.revalt = true;
							GameProgressSaver.AddGear(weaponIdFromName);
						}
						else
						{
							Core.data.revstd = true;
						}
						break;
					case "shoalt":
						if (Core.data.shoForm == WeaponForm.Standard)
						{
							Core.data.shoalt = true;
							GameProgressSaver.AddGear(weaponIdFromName);
						}
						else
						{
							Core.data.shostd = true;
						}
						break;
					case "naialt":
						if (Core.data.naiForm == WeaponForm.Standard)
						{
							Core.data.naialt = true;
							GameProgressSaver.AddGear(weaponIdFromName);
						}
						else
						{
							Core.data.naistd = true;
						}
						break;
					default:
						Core.Logger.LogWarning((object)("Unknown WeaponAlt: " + weaponIdFromName));
						break;
					}
					text3 = "WEAPON: ";
					break;
				}
				case UKType.Arm:
					if (Core.IsInLevel)
					{
						HudController.Instance.armIcon.SetActive(true);
					}
					if (item.itemName == "Feedbacker")
					{
						Core.data.hasArm = true;
						MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 1);
						if (Core.CanGetWeapon)
						{
							MonoSingleton<FistControl>.Instance.ResetFists();
							MonoSingleton<FistControl>.Instance.ForceArm(int.Parse(GetWeaponIdFromName(item.itemName).Substring(3, 1)), false);
						}
					}
					else
					{
						if (!Core.data.hasArm && item.itemName == "Knuckleblaster")
						{
							MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 0);
						}
						GameProgressSaver.AddGear(GetWeaponIdFromName(item.itemName));
						MonoSingleton<PrefsManager>.Instance.SetInt("weapon." + GetWeaponIdFromName(item.itemName), 1);
						if (Core.CanGetWeapon)
						{
							MonoSingleton<FistControl>.Instance.ResetFists();
							MonoSingleton<FistControl>.Instance.ForceArm(int.Parse(GetWeaponIdFromName(item.itemName).Substring(3, 1)), false);
						}
					}
					text3 = "ARM: ";
					break;
				case UKType.Ability:
					if (item.itemName == "Stamina Bar" && Core.data.dashes < 3)
					{
						Core.data.dashes++;
					}
					else if (item.itemName == "Wall Jump" && Core.data.walljumps < 3)
					{
						Core.data.walljumps++;
					}
					else if (item.itemName == "Slide")
					{
						Core.data.canSlide = true;
					}
					else if (item.itemName == "Slam")
					{
						Core.data.canSlam = true;
					}
					text3 = "ABILITY: ";
					break;
				case UKType.Skull:
					if (!Core.data.randomizeSkulls)
					{
						return;
					}
					if (item.itemName.Contains("1-4"))
					{
						if (Core.data.unlockedSkulls1_4 == 4)
						{
							return;
						}
						Core.data.unlockedSkulls1_4++;
						if (SceneHelper.CurrentScene == "Level 1-4")
						{
							LevelManager.ActivateSkull(LevelManager.skulls.ElementAt(Core.data.unlockedSkulls1_4 - 1).Value);
						}
					}
					else if (item.itemName.Contains("5-1"))
					{
						if (Core.data.unlockedSkulls5_1 == 3)
						{
							return;
						}
						Core.data.unlockedSkulls5_1++;
						if (SceneHelper.CurrentScene == "Level 5-1")
						{
							LevelManager.ActivateSkull(LevelManager.skulls.ElementAt(Core.data.unlockedSkulls5_1 - 1).Value);
						}
					}
					else if (item.itemName.Contains("0-S"))
					{
						if (item.itemName.Contains("Blue"))
						{
							Core.data.unlockedSkulls.Add("0S_b");
						}
						else if (item.itemName.Contains("Red"))
						{
							Core.data.unlockedSkulls.Add("0S_r");
						}
					}
					else if (item.itemName.Contains("7-S"))
					{
						if (item.itemName.Contains("Blue"))
						{
							Core.data.unlockedSkulls.Add("7S_b");
						}
						else if (item.itemName.Contains("Red"))
						{
							Core.data.unlockedSkulls.Add("7S_r");
						}
					}
					else
					{
						string text4 = Core.GetLevelIdFromName(item.itemName.Substring(item.itemName.Length - 4, 3)).ToString();
						if (item.itemName.Contains("Blue"))
						{
							text4 += "_b";
						}
						else if (item.itemName.Contains("Red"))
						{
							text4 += "_r";
						}
						Core.Logger.LogInfo((object)("Skull: " + text4));
						Core.data.unlockedSkulls.Add(text4);
					}
					if (SceneHelper.CurrentScene == "Level 0-S")
					{
						if (item.itemName == "Blue Skull (0-S)")
						{
							LevelManager.ActivateSkull(LevelManager.skulls["SkullBlue"]);
						}
						else if (item.itemName == "Red Skull (0-S)")
						{
							LevelManager.ActivateSkull(LevelManager.skulls["SkullRed"]);
						}
					}
					else if (SceneHelper.CurrentScene == "Level 7-S")
					{
						if (item.itemName == "Blue Skull (7-S)")
						{
							LevelManager.ActivateSkull(LevelManager.skulls["SkullBlue"]);
						}
						else if (item.itemName == "Red Skull (7-S)")
						{
							LevelManager.ActivateSkull(LevelManager.skulls["SkullRed"]);
						}
					}
					else if (MonoSingleton<StatsManager>.Instance.levelNumber != 0 && Core.IsInLevel && item.itemName.Contains(Core.GetLevelNameFromId(MonoSingleton<StatsManager>.Instance.levelNumber)))
					{
						if (item.itemName.Contains("Blue"))
						{
							LevelManager.ActivateSkull(LevelManager.skulls["SkullBlue"]);
						}
						else if (item.itemName.Contains("Red"))
						{
							if (Core.CurrentLevelInfo.Id == 101)
							{
								LevelManager.redDoor.Open(false, false);
							}
							else
							{
								LevelManager.ActivateSkull(LevelManager.skulls["SkullRed"]);
							}
						}
					}
					if (SceneHelper.CurrentScene == "Main Menu")
					{
						SkullIcon[] array = Object.FindObjectsOfType<SkullIcon>();
						foreach (SkullIcon skullIcon in array)
						{
							skullIcon.CheckSkull();
						}
					}
					text3 = ((sendingPlayer != null) ? "GOT: " : "FOUND: ");
					break;
				case UKType.Level:
					Core.data.unlockedLevels.Add(item.itemName.Substring(0, 3));
					text3 = "UNLOCKED: ";
					break;
				case UKType.SecretMission:
					GameProgressSaver.FoundSecretMission(int.Parse(item.itemName.Substring(0, 1)));
					text3 = "UNLOCKED: ";
					break;
				case UKType.Layer:
				{
					int num2 = ((!item.itemName.Contains("OVERTURE")) ? int.Parse(item.itemName[6].ToString()) : 0);
					foreach (LevelInfo levelInfo in Core.levelInfos)
					{
						if (levelInfo.Layer == num2)
						{
							Core.data.unlockedLevels.Add(levelInfo.Name);
						}
					}
					text3 = "UNLOCKED: ";
					break;
				}
				case UKType.Points:
					GameProgressSaver.AddMoney(10000);
					text3 = ((sendingPlayer != null) ? "GOT: " : "FOUND: ");
					break;
				case UKType.Powerup:
					switch (item.itemName)
					{
					case "Overheal":
						powerupQueue.Add(Powerup.Overheal);
						break;
					case "Dual Wield":
						powerupQueue.Add(Powerup.DualWield);
						break;
					case "Infinite Stamina":
						powerupQueue.Add(Powerup.InfiniteStamina);
						break;
					case "Air Jump":
						powerupQueue.Add(Powerup.DoubleJump);
						break;
					case "Confusing Aura":
						powerupQueue.Add(Powerup.Confusion);
						break;
					case "Quick Charge":
						powerupQueue.Add(Powerup.QuickCharge);
						break;
					default:
						Core.Logger.LogWarning((object)("Couldn't identify powerup: \"" + item.itemName + "\""));
						break;
					}
					text3 = ((sendingPlayer != null) ? "GOT: " : "FOUND: ");
					break;
				case UKType.Trap:
					switch (item.itemName)
					{
					case "Hard Damage":
						powerupQueue.Add(Powerup.HardDamage);
						break;
					case "Stamina Limiter":
						powerupQueue.Add(Powerup.StaminaLimiter);
						break;
					case "Wall Jump Limiter":
						powerupQueue.Add(Powerup.WalljumpLimiter);
						break;
					case "Empty Ammunition":
					case "Weapon Malfunction":
						powerupQueue.Add(Powerup.EmptyAmmo);
						break;
					case "Radiant Aura":
						powerupQueue.Add(Powerup.Radiance);
						break;
					case "Hands-Free Mode":
						powerupQueue.Add(Powerup.NoArms);
						break;
					case "Short-Term Sandstorm":
						powerupQueue.Add(Powerup.Sandstorm);
						break;
					default:
						Core.Logger.LogWarning((object)("Couldn't identify trap: \"" + item.itemName + "\""));
						break;
					}
					text3 = ((sendingPlayer != null) ? "GOT: " : "FOUND: ");
					break;
				case UKType.Soap:
					soapWaiting++;
					text3 = ((sendingPlayer != null) ? "GOT: " : "FOUND: ");
					break;
				case UKType.Fire2:
					Core.data.unlockedFire2.Add(GetWeaponIdFromName(item.itemName));
					if ((Object)(object)Fire2HUD.Instance != (Object)null)
					{
						Fire2HUD.Instance.UpdateCurrentWeapon();
					}
					text3 = "UNLOCKED: ";
					break;
				case UKType.LimboSwitch:
					if (item.itemName == "Limbo Switch I")
					{
						Core.data.limboSwitches[0] = true;
					}
					else if (item.itemName == "Limbo Switch II")
					{
						Core.data.limboSwitches[1] = true;
					}
					else if (item.itemName == "Limbo Switch III")
					{
						Core.data.limboSwitches[2] = true;
					}
					else if (item.itemName == "Limbo Switch IV")
					{
						Core.data.limboSwitches[3] = true;
					}
					if (Object.op_Implicit((Object)(object)Object.FindObjectOfType<LimboSwitchLock>()))
					{
						Traverse.Create((object)Object.FindObjectOfType<LimboSwitchLock>()).Field<int>("openedLocks").Value = 0;
						Object.FindObjectOfType<LimboSwitchLock>().CheckSaves();
						Traverse.Create((object)Object.FindObjectOfType<LimboSwitchLock>()).Method("CheckLocks", Array.Empty<object>()).GetValue();
					}
					text3 = "ACTIVATED: ";
					break;
				case UKType.ShotgunSwitch:
					if (item.itemName == "Violence Switch I")
					{
						Core.data.shotgunSwitches[0] = true;
					}
					else if (item.itemName == "Violence Switch II")
					{
						Core.data.shotgunSwitches[1] = true;
					}
					else if (item.itemName == "Violence Switch III")
					{
						Core.data.shotgunSwitches[2] = true;
					}
					if (Object.op_Implicit((Object)(object)Object.FindObjectOfType<LimboSwitchLock>()))
					{
						Traverse.Create((object)Object.FindObjectOfType<LimboSwitchLock>()).Field<int>("openedLocks").Value = 0;
						Object.FindObjectOfType<LimboSwitchLock>().CheckSaves();
						Traverse.Create((object)Object.FindObjectOfType<LimboSwitchLock>()).Method("CheckLocks", Array.Empty<object>()).GetValue();
					}
					text3 = "ACTIVATED: ";
					break;
				case UKType.ClashMode:
				{
					GameProgressMoneyAndGear val = GameProgressSaver.GetGeneralProgress();
					val.clashModeUnlocked = true;
					Traverse.Create(typeof(GameProgressSaver)).Method("WriteFile", new object[2]
					{
						Traverse.Create(typeof(GameProgressSaver)).Property<string>("generalProgressPath", (object[])null).Value,
						val
					}).GetValue();
					text3 = "UNLOCKED: ";
					break;
				}
				}
				text3 = text3 + "<color=#" + text + "FF>" + item.itemName.ToUpper() + "</color>";
				if (sendingPlayer != null)
				{
					text3 = text3 + " (<color=#" + text2 + "FF>" + sendingPlayer + "</color>)";
				}
				if (!silent)
				{
					messages.Add(new Message
					{
						image = GetItemDefinition(item.itemName).Image,
						color = GetItemDefinition(item.itemName).Color(),
						message = text3
					});
				}
			}
			else
			{
				text3 = "FOUND: <color=#" + text + "FF>" + item.itemName.ToUpper() + "</color> (<color=#" + text2 + "FF>" + item.playerName + "</color>)";
				if (!silent)
				{
					messages.Add(new Message
					{
						image = GetItemDefinition(item.itemName).Image,
						color = Colors.Gray,
						message = text3
					});
				}
			}
			if (save)
			{
				Core.SaveData();
			}
			ActStats.SetAllDirty();
		}

		public static void GetRandomHint()
		{
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			if (Multiworld.Session == null)
			{
				return;
			}
			ReadOnlyCollection<long> allMissingLocations = Multiworld.Session.Locations.AllMissingLocations;
			IEnumerable<long> second = from h in ((IDataStorageWrapper)Multiworld.Session.DataStorage).GetHintsAsync((int?)null, (int?)null).Result
				where h.FindingPlayer == Multiworld.Session.ConnectionInfo.Slot
				select h.LocationId;
			long[] array = allMissingLocations.Except(second).ToArray();
			if (array.Any())
			{
				long num = array[Random.Range(0, array.Length)];
				ScoutedItemInfo val = Multiworld.Session.Locations.ScoutLocationsAsync(true, new long[1] { num }).Result[num];
				string locationNameFromId = Multiworld.Session.Locations.GetLocationNameFromId(((ItemInfo)val).LocationId, Multiworld.Session.Players.GetPlayerInfo(Multiworld.Session.ConnectionInfo.Slot).Game);
				string text = "";
				Color white = Color.white;
				string image = "filler";
				if (((ItemInfo)val).ItemGame == "ULTRAKILL" && GetItemDefinition(((ItemInfo)val).ItemName) != null)
				{
					text = ColorUtility.ToHtmlStringRGB(GetItemDefinition(((ItemInfo)val).ItemName).Color());
					white = GetItemDefinition(((ItemInfo)val).ItemName).Color();
					image = GetItemDefinition(((ItemInfo)val).ItemName).Image;
				}
				else
				{
					text = ColorUtility.ToHtmlStringRGB(GetAPMessageColor(((ItemInfo)val).Flags));
					white = GetAPMessageColor(((ItemInfo)val).Flags);
				}
				string text2 = ColorUtility.ToHtmlStringRGB(Colors.PlayerOther);
				string text3 = ColorUtility.ToHtmlStringRGB(GetLocationColor(locationNameFromId.Substring(0, 3)));
				string text4 = "HINT: <color=#" + text + "FF>";
				text4 = text4 + ((ItemInfo)val).ItemName.ToUpper() + "</color> ";
				if (Multiworld.Session.Players.GetPlayerName(PlayerInfo.op_Implicit(val.Player)) != Core.data.slot_name)
				{
					text4 = text4 + "(<color=#" + text2 + "FF>" + Multiworld.Session.Players.GetPlayerAlias(PlayerInfo.op_Implicit(val.Player)) + "</color>) ";
				}
				text4 = text4 + "at <color=#" + text3 + "FF>" + ((ItemInfo)val).LocationName + "</color>";
				messages.Add(new Message
				{
					image = image,
					color = white,
					message = text4
				});
				if (!UIManager.displayingMessage && (Core.IsPlaying || SceneHelper.CurrentScene == "Endless"))
				{
					((MonoBehaviour)Core.uim).StartCoroutine("DisplayMessage");
				}
			}
			else
			{
				Core.Logger.LogWarning((object)"No locations available to hint.");
			}
		}

		public static Color GetLocationColor(string locationName)
		{
			//IL_0010: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL o

websocket-sharp.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Timers;
using WebSocketSharp.Net;
using WebSocketSharp.Net.WebSockets;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("websocket-sharp")]
[assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("websocket-sharp.dll")]
[assembly: AssemblyCopyright("sta.blockhead")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("1.0.2.34775")]
namespace WebSocketSharp
{
	public static class Ext
	{
		private static readonly byte[] _last = new byte[1];

		private static readonly int _retry = 5;

		private const string _tspecials = "()<>@,;:\\\"/[]?={} \t";

		private static byte[] compress(this byte[] data)
		{
			if (data.LongLength == 0)
			{
				return data;
			}
			using MemoryStream stream = new MemoryStream(data);
			return stream.compressToArray();
		}

		private static MemoryStream compress(this Stream stream)
		{
			MemoryStream memoryStream = new MemoryStream();
			if (stream.Length == 0)
			{
				return memoryStream;
			}
			stream.Position = 0L;
			using DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, leaveOpen: true);
			CopyTo(stream, deflateStream, 1024);
			deflateStream.Close();
			memoryStream.Write(_last, 0, 1);
			memoryStream.Position = 0L;
			return memoryStream;
		}

		private static byte[] compressToArray(this Stream stream)
		{
			using MemoryStream memoryStream = stream.compress();
			memoryStream.Close();
			return memoryStream.ToArray();
		}

		private static byte[] decompress(this byte[] data)
		{
			if (data.LongLength == 0)
			{
				return data;
			}
			using MemoryStream stream = new MemoryStream(data);
			return stream.decompressToArray();
		}

		private static MemoryStream decompress(this Stream stream)
		{
			MemoryStream memoryStream = new MemoryStream();
			if (stream.Length == 0)
			{
				return memoryStream;
			}
			stream.Position = 0L;
			using DeflateStream source = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true);
			CopyTo(source, memoryStream, 1024);
			memoryStream.Position = 0L;
			return memoryStream;
		}

		private static byte[] decompressToArray(this Stream stream)
		{
			using MemoryStream memoryStream = stream.decompress();
			memoryStream.Close();
			return memoryStream.ToArray();
		}

		private static bool isHttpMethod(this string value)
		{
			int result;
			switch (value)
			{
			default:
				result = ((value == "TRACE") ? 1 : 0);
				break;
			case "GET":
			case "HEAD":
			case "POST":
			case "PUT":
			case "DELETE":
			case "CONNECT":
			case "OPTIONS":
				result = 1;
				break;
			}
			return (byte)result != 0;
		}

		private static bool isHttpMethod10(this string value)
		{
			return value == "GET" || value == "HEAD" || value == "POST";
		}

		internal static byte[] Append(this ushort code, string reason)
		{
			byte[] array = code.InternalToByteArray(ByteOrder.Big);
			if (reason == null || reason.Length == 0)
			{
				return array;
			}
			List<byte> list = new List<byte>(array);
			list.AddRange(Encoding.UTF8.GetBytes(reason));
			return list.ToArray();
		}

		internal static byte[] Compress(this byte[] data, CompressionMethod method)
		{
			return (method == CompressionMethod.Deflate) ? data.compress() : data;
		}

		internal static Stream Compress(this Stream stream, CompressionMethod method)
		{
			return (method == CompressionMethod.Deflate) ? stream.compress() : stream;
		}

		internal static byte[] CompressToArray(this Stream stream, CompressionMethod method)
		{
			return (method == CompressionMethod.Deflate) ? stream.compressToArray() : stream.ToByteArray();
		}

		internal static bool Contains(this string value, params char[] anyOf)
		{
			return anyOf != null && anyOf.Length != 0 && value.IndexOfAny(anyOf) > -1;
		}

		internal static bool Contains(this NameValueCollection collection, string name)
		{
			return collection[name] != null;
		}

		internal static bool Contains(this NameValueCollection collection, string name, string value, StringComparison comparisonTypeForValue)
		{
			string text = collection[name];
			if (text == null)
			{
				return false;
			}
			string[] array = text.Split(new char[1] { ',' });
			foreach (string text2 in array)
			{
				if (text2.Trim().Equals(value, comparisonTypeForValue))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool Contains<T>(this IEnumerable<T> source, Func<T, bool> condition)
		{
			foreach (T item in source)
			{
				if (condition(item))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool ContainsTwice(this string[] values)
		{
			int len = values.Length;
			int end = len - 1;
			Func<int, bool> seek = null;
			seek = delegate(int idx)
			{
				if (idx == end)
				{
					return false;
				}
				string text = values[idx];
				for (int i = idx + 1; i < len; i++)
				{
					if (values[i] == text)
					{
						return true;
					}
				}
				return seek(++idx);
			};
			return seek(0);
		}

		internal static T[] Copy<T>(this T[] source, int length)
		{
			T[] array = new T[length];
			Array.Copy(source, 0, array, 0, length);
			return array;
		}

		internal static T[] Copy<T>(this T[] source, long length)
		{
			T[] array = new T[length];
			Array.Copy(source, 0L, array, 0L, length);
			return array;
		}

		internal static void CopyTo(this Stream source, Stream destination, int bufferLength)
		{
			byte[] buffer = new byte[bufferLength];
			int num = 0;
			while (true)
			{
				num = source.Read(buffer, 0, bufferLength);
				if (num <= 0)
				{
					break;
				}
				destination.Write(buffer, 0, num);
			}
		}

		internal static void CopyToAsync(this Stream source, Stream destination, int bufferLength, Action completed, Action<Exception> error)
		{
			byte[] buff = new byte[bufferLength];
			AsyncCallback callback = null;
			callback = delegate(IAsyncResult ar)
			{
				try
				{
					int num = source.EndRead(ar);
					if (num <= 0)
					{
						if (completed != null)
						{
							completed();
						}
					}
					else
					{
						destination.Write(buff, 0, num);
						source.BeginRead(buff, 0, bufferLength, callback, null);
					}
				}
				catch (Exception obj2)
				{
					if (error != null)
					{
						error(obj2);
					}
				}
			};
			try
			{
				source.BeginRead(buff, 0, bufferLength, callback, null);
			}
			catch (Exception obj)
			{
				if (error != null)
				{
					error(obj);
				}
			}
		}

		internal static byte[] Decompress(this byte[] data, CompressionMethod method)
		{
			return (method == CompressionMethod.Deflate) ? data.decompress() : data;
		}

		internal static Stream Decompress(this Stream stream, CompressionMethod method)
		{
			return (method == CompressionMethod.Deflate) ? stream.decompress() : stream;
		}

		internal static byte[] DecompressToArray(this Stream stream, CompressionMethod method)
		{
			return (method == CompressionMethod.Deflate) ? stream.decompressToArray() : stream.ToByteArray();
		}

		internal static void Emit(this EventHandler eventHandler, object sender, EventArgs e)
		{
			eventHandler?.Invoke(sender, e);
		}

		internal static void Emit<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) where TEventArgs : EventArgs
		{
			eventHandler?.Invoke(sender, e);
		}

		internal static bool EqualsWith(this int value, char c, Action<int> action)
		{
			action(value);
			return value == c;
		}

		internal static string GetAbsolutePath(this Uri uri)
		{
			if (uri.IsAbsoluteUri)
			{
				return uri.AbsolutePath;
			}
			string originalString = uri.OriginalString;
			if (originalString[0] != '/')
			{
				return null;
			}
			int num = originalString.IndexOfAny(new char[2] { '?', '#' });
			return (num > 0) ? originalString.Substring(0, num) : originalString;
		}

		internal static WebSocketSharp.Net.CookieCollection GetCookies(this NameValueCollection headers, bool response)
		{
			string text = headers[response ? "Set-Cookie" : "Cookie"];
			return (text != null) ? WebSocketSharp.Net.CookieCollection.Parse(text, response) : new WebSocketSharp.Net.CookieCollection();
		}

		internal static string GetDnsSafeHost(this Uri uri, bool bracketIPv6)
		{
			return (bracketIPv6 && uri.HostNameType == UriHostNameType.IPv6) ? uri.Host : uri.DnsSafeHost;
		}

		internal static string GetMessage(this CloseStatusCode code)
		{
			return code switch
			{
				CloseStatusCode.TlsHandshakeFailure => "An error has occurred during a TLS handshake.", 
				CloseStatusCode.ServerError => "WebSocket server got an internal error.", 
				CloseStatusCode.MandatoryExtension => "WebSocket client didn't receive expected extension(s).", 
				CloseStatusCode.TooBig => "A too big message has been received.", 
				CloseStatusCode.PolicyViolation => "A policy violation has occurred.", 
				CloseStatusCode.InvalidData => "Invalid data has been received.", 
				CloseStatusCode.Abnormal => "An exception has occurred.", 
				CloseStatusCode.UnsupportedData => "Unsupported data has been received.", 
				CloseStatusCode.ProtocolError => "A WebSocket protocol error has occurred.", 
				_ => string.Empty, 
			};
		}

		internal static string GetName(this string nameAndValue, char separator)
		{
			int num = nameAndValue.IndexOf(separator);
			return (num > 0) ? nameAndValue.Substring(0, num).Trim() : null;
		}

		internal static string GetUTF8DecodedString(this byte[] bytes)
		{
			return Encoding.UTF8.GetString(bytes);
		}

		internal static byte[] GetUTF8EncodedBytes(this string s)
		{
			return Encoding.UTF8.GetBytes(s);
		}

		internal static string GetValue(this string nameAndValue, char separator)
		{
			return nameAndValue.GetValue(separator, unquote: false);
		}

		internal static string GetValue(this string nameAndValue, char separator, bool unquote)
		{
			int num = nameAndValue.IndexOf(separator);
			if (num < 0 || num == nameAndValue.Length - 1)
			{
				return null;
			}
			string text = nameAndValue.Substring(num + 1).Trim();
			return unquote ? text.Unquote() : text;
		}

		internal static byte[] InternalToByteArray(this ushort value, ByteOrder order)
		{
			byte[] bytes = BitConverter.GetBytes(value);
			if (!order.IsHostOrder())
			{
				Array.Reverse((Array)bytes);
			}
			return bytes;
		}

		internal static byte[] InternalToByteArray(this ulong value, ByteOrder order)
		{
			byte[] bytes = BitConverter.GetBytes(value);
			if (!order.IsHostOrder())
			{
				Array.Reverse((Array)bytes);
			}
			return bytes;
		}

		internal static bool IsCompressionExtension(this string value, CompressionMethod method)
		{
			return value.StartsWith(method.ToExtensionString());
		}

		internal static bool IsControl(this byte opcode)
		{
			return opcode > 7 && opcode < 16;
		}

		internal static bool IsControl(this Opcode opcode)
		{
			return (int)opcode >= 8;
		}

		internal static bool IsData(this byte opcode)
		{
			return opcode == 1 || opcode == 2;
		}

		internal static bool IsData(this Opcode opcode)
		{
			return opcode == Opcode.Text || opcode == Opcode.Binary;
		}

		internal static bool IsHttpMethod(this string value, Version version)
		{
			return (version == WebSocketSharp.Net.HttpVersion.Version10) ? value.isHttpMethod10() : value.isHttpMethod();
		}

		internal static bool IsPortNumber(this int value)
		{
			return value > 0 && value < 65536;
		}

		internal static bool IsReserved(this ushort code)
		{
			return code == 1004 || code == 1005 || code == 1006 || code == 1015;
		}

		internal static bool IsReserved(this CloseStatusCode code)
		{
			return code == CloseStatusCode.Undefined || code == CloseStatusCode.NoStatus || code == CloseStatusCode.Abnormal || code == CloseStatusCode.TlsHandshakeFailure;
		}

		internal static bool IsSupported(this byte opcode)
		{
			return Enum.IsDefined(typeof(Opcode), opcode);
		}

		internal static bool IsText(this string value)
		{
			int length = value.Length;
			for (int i = 0; i < length; i++)
			{
				char c = value[i];
				if (c < ' ')
				{
					if ("\r\n\t".IndexOf(c) == -1)
					{
						return false;
					}
					if (c == '\n')
					{
						i++;
						if (i == length)
						{
							break;
						}
						c = value[i];
						if (" \t".IndexOf(c) == -1)
						{
							return false;
						}
					}
				}
				else if (c == '\u007f')
				{
					return false;
				}
			}
			return true;
		}

		internal static bool IsToken(this string value)
		{
			foreach (char c in value)
			{
				if (c < ' ')
				{
					return false;
				}
				if (c > '~')
				{
					return false;
				}
				if ("()<>@,;:\\\"/[]?={} \t".IndexOf(c) > -1)
				{
					return false;
				}
			}
			return true;
		}

		internal static bool KeepsAlive(this NameValueCollection headers, Version version)
		{
			StringComparison comparisonTypeForValue = StringComparison.OrdinalIgnoreCase;
			return (version < WebSocketSharp.Net.HttpVersion.Version11) ? headers.Contains("Connection", "keep-alive", comparisonTypeForValue) : (!headers.Contains("Connection", "close", comparisonTypeForValue));
		}

		internal static string Quote(this string value)
		{
			return string.Format("\"{0}\"", value.Replace("\"", "\\\""));
		}

		internal static byte[] ReadBytes(this Stream stream, int length)
		{
			byte[] array = new byte[length];
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			while (length > 0)
			{
				num3 = stream.Read(array, num, length);
				if (num3 <= 0)
				{
					if (num2 >= _retry)
					{
						return array.SubArray(0, num);
					}
					num2++;
				}
				else
				{
					num2 = 0;
					num += num3;
					length -= num3;
				}
			}
			return array;
		}

		internal static byte[] ReadBytes(this Stream stream, long length, int bufferLength)
		{
			using MemoryStream memoryStream = new MemoryStream();
			byte[] buffer = new byte[bufferLength];
			int num = 0;
			int num2 = 0;
			while (length > 0)
			{
				if (length < bufferLength)
				{
					bufferLength = (int)length;
				}
				num2 = stream.Read(buffer, 0, bufferLength);
				if (num2 <= 0)
				{
					if (num >= _retry)
					{
						break;
					}
					num++;
				}
				else
				{
					num = 0;
					memoryStream.Write(buffer, 0, num2);
					length -= num2;
				}
			}
			memoryStream.Close();
			return memoryStream.ToArray();
		}

		internal static void ReadBytesAsync(this Stream stream, int length, Action<byte[]> completed, Action<Exception> error)
		{
			byte[] buff = new byte[length];
			int offset = 0;
			int retry = 0;
			AsyncCallback callback = null;
			callback = delegate(IAsyncResult ar)
			{
				try
				{
					int num = stream.EndRead(ar);
					if (num <= 0)
					{
						if (retry < _retry)
						{
							retry++;
							stream.BeginRead(buff, offset, length, callback, null);
						}
						else if (completed != null)
						{
							completed(buff.SubArray(0, offset));
						}
					}
					else if (num == length)
					{
						if (completed != null)
						{
							completed(buff);
						}
					}
					else
					{
						retry = 0;
						offset += num;
						length -= num;
						stream.BeginRead(buff, offset, length, callback, null);
					}
				}
				catch (Exception obj2)
				{
					if (error != null)
					{
						error(obj2);
					}
				}
			};
			try
			{
				stream.BeginRead(buff, offset, length, callback, null);
			}
			catch (Exception obj)
			{
				if (error != null)
				{
					error(obj);
				}
			}
		}

		internal static void ReadBytesAsync(this Stream stream, long length, int bufferLength, Action<byte[]> completed, Action<Exception> error)
		{
			MemoryStream dest = new MemoryStream();
			byte[] buff = new byte[bufferLength];
			int retry = 0;
			Action<long> read = null;
			read = delegate(long len)
			{
				if (len < bufferLength)
				{
					bufferLength = (int)len;
				}
				stream.BeginRead(buff, 0, bufferLength, delegate(IAsyncResult ar)
				{
					try
					{
						int num = stream.EndRead(ar);
						if (num <= 0)
						{
							if (retry < _retry)
							{
								int num2 = retry;
								retry = num2 + 1;
								read(len);
							}
							else
							{
								if (completed != null)
								{
									dest.Close();
									completed(dest.ToArray());
								}
								dest.Dispose();
							}
						}
						else
						{
							dest.Write(buff, 0, num);
							if (num == len)
							{
								if (completed != null)
								{
									dest.Close();
									completed(dest.ToArray());
								}
								dest.Dispose();
							}
							else
							{
								retry = 0;
								read(len - num);
							}
						}
					}
					catch (Exception obj2)
					{
						dest.Dispose();
						if (error != null)
						{
							error(obj2);
						}
					}
				}, null);
			};
			try
			{
				read(length);
			}
			catch (Exception obj)
			{
				dest.Dispose();
				if (error != null)
				{
					error(obj);
				}
			}
		}

		internal static T[] Reverse<T>(this T[] array)
		{
			int num = array.Length;
			T[] array2 = new T[num];
			int num2 = num - 1;
			for (int i = 0; i <= num2; i++)
			{
				array2[i] = array[num2 - i];
			}
			return array2;
		}

		internal static IEnumerable<string> SplitHeaderValue(this string value, params char[] separators)
		{
			int len = value.Length;
			int end = len - 1;
			StringBuilder buff = new StringBuilder(32);
			bool escaped = false;
			bool quoted = false;
			for (int i = 0; i <= end; i++)
			{
				char c = value[i];
				buff.Append(c);
				switch (c)
				{
				case '"':
					if (escaped)
					{
						escaped = false;
					}
					else
					{
						quoted = !quoted;
					}
					continue;
				case '\\':
					if (i == end)
					{
						break;
					}
					if (value[i + 1] == '"')
					{
						escaped = true;
					}
					continue;
				default:
					if (Array.IndexOf(separators, c) > -1 && !quoted)
					{
						buff.Length--;
						yield return buff.ToString();
						buff.Length = 0;
					}
					continue;
				}
				break;
			}
			yield return buff.ToString();
		}

		internal static byte[] ToByteArray(this Stream stream)
		{
			using MemoryStream memoryStream = new MemoryStream();
			stream.Position = 0L;
			CopyTo(stream, memoryStream, 1024);
			memoryStream.Close();
			return memoryStream.ToArray();
		}

		internal static CompressionMethod ToCompressionMethod(this string value)
		{
			Array values = Enum.GetValues(typeof(CompressionMethod));
			foreach (CompressionMethod item in values)
			{
				if (item.ToExtensionString() == value)
				{
					return item;
				}
			}
			return CompressionMethod.None;
		}

		internal static string ToExtensionString(this CompressionMethod method, params string[] parameters)
		{
			if (method == CompressionMethod.None)
			{
				return string.Empty;
			}
			string text = $"permessage-{method.ToString().ToLower()}";
			return (parameters != null && parameters.Length != 0) ? string.Format("{0}; {1}", text, parameters.ToString("; ")) : text;
		}

		internal static IPAddress ToIPAddress(this string value)
		{
			if (value == null || value.Length == 0)
			{
				return null;
			}
			if (IPAddress.TryParse(value, out IPAddress address))
			{
				return address;
			}
			try
			{
				IPAddress[] hostAddresses = Dns.GetHostAddresses(value);
				return hostAddresses[0];
			}
			catch
			{
				return null;
			}
		}

		internal static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
		{
			return new List<TSource>(source);
		}

		internal static string ToString(this IPAddress address, bool bracketIPv6)
		{
			return (bracketIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6) ? $"[{address.ToString()}]" : address.ToString();
		}

		internal static ushort ToUInt16(this byte[] source, ByteOrder sourceOrder)
		{
			return BitConverter.ToUInt16(source.ToHostOrder(sourceOrder), 0);
		}

		internal static ulong ToUInt64(this byte[] source, ByteOrder sourceOrder)
		{
			return BitConverter.ToUInt64(source.ToHostOrder(sourceOrder), 0);
		}

		internal static IEnumerable<string> TrimEach(this IEnumerable<string> source)
		{
			foreach (string elm in source)
			{
				yield return elm.Trim();
			}
		}

		internal static string TrimSlashFromEnd(this string value)
		{
			string text = value.TrimEnd(new char[1] { '/' });
			return (text.Length > 0) ? text : "/";
		}

		internal static string TrimSlashOrBackslashFromEnd(this string value)
		{
			string text = value.TrimEnd('/', '\\');
			return (text.Length > 0) ? text : value[0].ToString();
		}

		internal static bool TryCreateVersion(this string versionString, out Version result)
		{
			result = null;
			try
			{
				result = new Version(versionString);
			}
			catch
			{
				return false;
			}
			return true;
		}

		internal static bool TryCreateWebSocketUri(this string uriString, out Uri result, out string message)
		{
			result = null;
			message = null;
			Uri uri = uriString.ToUri();
			if (uri == null)
			{
				message = "An invalid URI string.";
				return false;
			}
			if (!uri.IsAbsoluteUri)
			{
				message = "A relative URI.";
				return false;
			}
			string scheme = uri.Scheme;
			if (!(scheme == "ws") && !(scheme == "wss"))
			{
				message = "The scheme part is not 'ws' or 'wss'.";
				return false;
			}
			int port = uri.Port;
			if (port == 0)
			{
				message = "The port part is zero.";
				return false;
			}
			if (uri.Fragment.Length > 0)
			{
				message = "It includes the fragment component.";
				return false;
			}
			result = ((port != -1) ? uri : new Uri(string.Format("{0}://{1}:{2}{3}", scheme, uri.Host, (scheme == "ws") ? 80 : 443, uri.PathAndQuery)));
			return true;
		}

		internal static bool TryGetUTF8DecodedString(this byte[] bytes, out string s)
		{
			s = null;
			try
			{
				s = Encoding.UTF8.GetString(bytes);
			}
			catch
			{
				return false;
			}
			return true;
		}

		internal static bool TryGetUTF8EncodedBytes(this string s, out byte[] bytes)
		{
			bytes = null;
			try
			{
				bytes = Encoding.UTF8.GetBytes(s);
			}
			catch
			{
				return false;
			}
			return true;
		}

		internal static bool TryOpenRead(this FileInfo fileInfo, out FileStream fileStream)
		{
			fileStream = null;
			try
			{
				fileStream = fileInfo.OpenRead();
			}
			catch
			{
				return false;
			}
			return true;
		}

		internal static string Unquote(this string value)
		{
			int num = value.IndexOf('"');
			if (num == -1)
			{
				return value;
			}
			int num2 = value.LastIndexOf('"');
			if (num2 == num)
			{
				return value;
			}
			int num3 = num2 - num - 1;
			return (num3 > 0) ? value.Substring(num + 1, num3).Replace("\\\"", "\"") : string.Empty;
		}

		internal static bool Upgrades(this NameValueCollection headers, string protocol)
		{
			StringComparison comparisonTypeForValue = StringComparison.OrdinalIgnoreCase;
			return headers.Contains("Upgrade", protocol, comparisonTypeForValue) && headers.Contains("Connection", "Upgrade", comparisonTypeForValue);
		}

		internal static string UrlDecode(this string value, Encoding encoding)
		{
			return HttpUtility.UrlDecode(value, encoding);
		}

		internal static string UrlEncode(this string value, Encoding encoding)
		{
			return HttpUtility.UrlEncode(value, encoding);
		}

		internal static void WriteBytes(this Stream stream, byte[] bytes, int bufferLength)
		{
			using MemoryStream source = new MemoryStream(bytes);
			CopyTo(source, stream, bufferLength);
		}

		internal static void WriteBytesAsync(this Stream stream, byte[] bytes, int bufferLength, Action completed, Action<Exception> error)
		{
			MemoryStream src = new MemoryStream(bytes);
			src.CopyToAsync(stream, bufferLength, delegate
			{
				if (completed != null)
				{
					completed();
				}
				src.Dispose();
			}, delegate(Exception ex)
			{
				src.Dispose();
				if (error != null)
				{
					error(ex);
				}
			});
		}

		public static string GetDescription(this WebSocketSharp.Net.HttpStatusCode code)
		{
			return ((int)code).GetStatusDescription();
		}

		public static string GetStatusDescription(this int code)
		{
			return code switch
			{
				100 => "Continue", 
				101 => "Switching Protocols", 
				102 => "Processing", 
				200 => "OK", 
				201 => "Created", 
				202 => "Accepted", 
				203 => "Non-Authoritative Information", 
				204 => "No Content", 
				205 => "Reset Content", 
				206 => "Partial Content", 
				207 => "Multi-Status", 
				300 => "Multiple Choices", 
				301 => "Moved Permanently", 
				302 => "Found", 
				303 => "See Other", 
				304 => "Not Modified", 
				305 => "Use Proxy", 
				307 => "Temporary Redirect", 
				400 => "Bad Request", 
				401 => "Unauthorized", 
				402 => "Payment Required", 
				403 => "Forbidden", 
				404 => "Not Found", 
				405 => "Method Not Allowed", 
				406 => "Not Acceptable", 
				407 => "Proxy Authentication Required", 
				408 => "Request Timeout", 
				409 => "Conflict", 
				410 => "Gone", 
				411 => "Length Required", 
				412 => "Precondition Failed", 
				413 => "Request Entity Too Large", 
				414 => "Request-Uri Too Long", 
				415 => "Unsupported Media Type", 
				416 => "Requested Range Not Satisfiable", 
				417 => "Expectation Failed", 
				422 => "Unprocessable Entity", 
				423 => "Locked", 
				424 => "Failed Dependency", 
				500 => "Internal Server Error", 
				501 => "Not Implemented", 
				502 => "Bad Gateway", 
				503 => "Service Unavailable", 
				504 => "Gateway Timeout", 
				505 => "Http Version Not Supported", 
				507 => "Insufficient Storage", 
				_ => string.Empty, 
			};
		}

		public static bool IsCloseStatusCode(this ushort value)
		{
			return value > 999 && value < 5000;
		}

		public static bool IsEnclosedIn(this string value, char c)
		{
			if (value == null)
			{
				return false;
			}
			int length = value.Length;
			if (length < 2)
			{
				return false;
			}
			return value[0] == c && value[length - 1] == c;
		}

		public static bool IsHostOrder(this ByteOrder order)
		{
			return BitConverter.IsLittleEndian == (order == ByteOrder.Little);
		}

		public static bool IsLocal(this IPAddress address)
		{
			if (address == null)
			{
				throw new ArgumentNullException("address");
			}
			if (address.Equals(IPAddress.Any))
			{
				return true;
			}
			if (address.Equals(IPAddress.Loopback))
			{
				return true;
			}
			if (Socket.OSSupportsIPv6)
			{
				if (address.Equals(IPAddress.IPv6Any))
				{
					return true;
				}
				if (address.Equals(IPAddress.IPv6Loopback))
				{
					return true;
				}
			}
			string hostName = Dns.GetHostName();
			IPAddress[] hostAddresses = Dns.GetHostAddresses(hostName);
			IPAddress[] array = hostAddresses;
			foreach (IPAddress obj in array)
			{
				if (address.Equals(obj))
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsNullOrEmpty(this string value)
		{
			return value == null || value.Length == 0;
		}

		public static bool IsPredefinedScheme(this string value)
		{
			if (value == null || value.Length < 2)
			{
				return false;
			}
			switch (value[0])
			{
			case 'h':
				return value == "http" || value == "https";
			case 'w':
				return value == "ws" || value == "wss";
			case 'f':
				return value == "file" || value == "ftp";
			case 'g':
				return value == "gopher";
			case 'm':
				return value == "mailto";
			case 'n':
			{
				char c = value[1];
				return (c != 'e') ? (value == "nntp") : (value == "news" || value == "net.pipe" || value == "net.tcp");
			}
			default:
				return false;
			}
		}

		public static bool MaybeUri(this string value)
		{
			if (value == null)
			{
				return false;
			}
			if (value.Length == 0)
			{
				return false;
			}
			int num = value.IndexOf(':');
			if (num == -1)
			{
				return false;
			}
			if (num >= 10)
			{
				return false;
			}
			string value2 = value.Substring(0, num);
			return value2.IsPredefinedScheme();
		}

		public static T[] SubArray<T>(this T[] array, int startIndex, int length)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			int num = array.Length;
			if (num == 0)
			{
				if (startIndex != 0)
				{
					throw new ArgumentOutOfRangeException("startIndex");
				}
				if (length != 0)
				{
					throw new ArgumentOutOfRangeException("length");
				}
				return array;
			}
			if (startIndex < 0 || startIndex >= num)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (length < 0 || length > num - startIndex)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			if (length == 0)
			{
				return new T[0];
			}
			if (length == num)
			{
				return array;
			}
			T[] array2 = new T[length];
			Array.Copy(array, startIndex, array2, 0, length);
			return array2;
		}

		public static T[] SubArray<T>(this T[] array, long startIndex, long length)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			long num = array.LongLength;
			if (num == 0)
			{
				if (startIndex != 0)
				{
					throw new ArgumentOutOfRangeException("startIndex");
				}
				if (length != 0)
				{
					throw new ArgumentOutOfRangeException("length");
				}
				return array;
			}
			if (startIndex < 0 || startIndex >= num)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (length < 0 || length > num - startIndex)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			if (length == 0)
			{
				return new T[0];
			}
			if (length == num)
			{
				return array;
			}
			T[] array2 = new T[length];
			Array.Copy(array, startIndex, array2, 0L, length);
			return array2;
		}

		public static void Times(this int n, Action action)
		{
			if (n > 0 && action != null)
			{
				for (int i = 0; i < n; i++)
				{
					action();
				}
			}
		}

		public static void Times(this long n, Action action)
		{
			if (n > 0 && action != null)
			{
				for (long num = 0L; num < n; num++)
				{
					action();
				}
			}
		}

		public static void Times(this uint n, Action action)
		{
			if (n != 0 && action != null)
			{
				for (uint num = 0u; num < n; num++)
				{
					action();
				}
			}
		}

		public static void Times(this ulong n, Action action)
		{
			if (n != 0 && action != null)
			{
				for (ulong num = 0uL; num < n; num++)
				{
					action();
				}
			}
		}

		public static void Times(this int n, Action<int> action)
		{
			if (n > 0 && action != null)
			{
				for (int i = 0; i < n; i++)
				{
					action(i);
				}
			}
		}

		public static void Times(this long n, Action<long> action)
		{
			if (n > 0 && action != null)
			{
				for (long num = 0L; num < n; num++)
				{
					action(num);
				}
			}
		}

		public static void Times(this uint n, Action<uint> action)
		{
			if (n != 0 && action != null)
			{
				for (uint num = 0u; num < n; num++)
				{
					action(num);
				}
			}
		}

		public static void Times(this ulong n, Action<ulong> action)
		{
			if (n != 0 && action != null)
			{
				for (ulong num = 0uL; num < n; num++)
				{
					action(num);
				}
			}
		}

		[Obsolete("This method will be removed.")]
		public static T To<T>(this byte[] source, ByteOrder sourceOrder) where T : struct
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (source.Length == 0)
			{
				return default(T);
			}
			Type typeFromHandle = typeof(T);
			byte[] value = source.ToHostOrder(sourceOrder);
			return ((object)typeFromHandle == typeof(bool)) ? ((T)(object)BitConverter.ToBoolean(value, 0)) : (((object)typeFromHandle == typeof(char)) ? ((T)(object)BitConverter.ToChar(value, 0)) : (((object)typeFromHandle == typeof(double)) ? ((T)(object)BitConverter.ToDouble(value, 0)) : (((object)typeFromHandle == typeof(short)) ? ((T)(object)BitConverter.ToInt16(value, 0)) : (((object)typeFromHandle == typeof(int)) ? ((T)(object)BitConverter.ToInt32(value, 0)) : (((object)typeFromHandle == typeof(long)) ? ((T)(object)BitConverter.ToInt64(value, 0)) : (((object)typeFromHandle == typeof(float)) ? ((T)(object)BitConverter.ToSingle(value, 0)) : (((object)typeFromHandle == typeof(ushort)) ? ((T)(object)BitConverter.ToUInt16(value, 0)) : (((object)typeFromHandle == typeof(uint)) ? ((T)(object)BitConverter.ToUInt32(value, 0)) : (((object)typeFromHandle == typeof(ulong)) ? ((T)(object)BitConverter.ToUInt64(value, 0)) : default(T))))))))));
		}

		[Obsolete("This method will be removed.")]
		public static byte[] ToByteArray<T>(this T value, ByteOrder order) where T : struct
		{
			Type typeFromHandle = typeof(T);
			byte[] array = (((object)typeFromHandle == typeof(bool)) ? BitConverter.GetBytes((bool)(object)value) : (((object)typeFromHandle != typeof(byte)) ? (((object)typeFromHandle == typeof(char)) ? BitConverter.GetBytes((char)(object)value) : (((object)typeFromHandle == typeof(double)) ? BitConverter.GetBytes((double)(object)value) : (((object)typeFromHandle == typeof(short)) ? BitConverter.GetBytes((short)(object)value) : (((object)typeFromHandle == typeof(int)) ? BitConverter.GetBytes((int)(object)value) : (((object)typeFromHandle == typeof(long)) ? BitConverter.GetBytes((long)(object)value) : (((object)typeFromHandle == typeof(float)) ? BitConverter.GetBytes((float)(object)value) : (((object)typeFromHandle == typeof(ushort)) ? BitConverter.GetBytes((ushort)(object)value) : (((object)typeFromHandle == typeof(uint)) ? BitConverter.GetBytes((uint)(object)value) : (((object)typeFromHandle == typeof(ulong)) ? BitConverter.GetBytes((ulong)(object)value) : WebSocket.EmptyBytes))))))))) : new byte[1] { (byte)(object)value }));
			if (array.Length > 1 && !order.IsHostOrder())
			{
				Array.Reverse((Array)array);
			}
			return array;
		}

		public static byte[] ToHostOrder(this byte[] source, ByteOrder sourceOrder)
		{
			if (source == null)
			{
				throw new ArgumentNullException("source");
			}
			if (source.Length < 2)
			{
				return source;
			}
			if (sourceOrder.IsHostOrder())
			{
				return source;
			}
			return source.Reverse();
		}

		public static string ToString<T>(this T[] array, string separator)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}
			int num = array.Length;
			if (num == 0)
			{
				return string.Empty;
			}
			if (separator == null)
			{
				separator = string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(64);
			int num2 = num - 1;
			for (int i = 0; i < num2; i++)
			{
				stringBuilder.AppendFormat("{0}{1}", array[i], separator);
			}
			stringBuilder.Append(array[num2].ToString());
			return stringBuilder.ToString();
		}

		public static Uri ToUri(this string value)
		{
			Uri.TryCreate(value, value.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out Uri result);
			return result;
		}

		[Obsolete("This method will be removed.")]
		public static void WriteContent(this WebSocketSharp.Net.HttpListenerResponse response, byte[] content)
		{
			if (response == null)
			{
				throw new ArgumentNullException("response");
			}
			if (content == null)
			{
				throw new ArgumentNullException("content");
			}
			long num = content.LongLength;
			if (num == 0)
			{
				response.Close();
				return;
			}
			response.ContentLength64 = num;
			Stream outputStream = response.OutputStream;
			if (num <= int.MaxValue)
			{
				outputStream.Write(content, 0, (int)num);
			}
			else
			{
				outputStream.WriteBytes(content, 1024);
			}
			outputStream.Close();
		}
	}
	public class MessageEventArgs : EventArgs
	{
		private string _data;

		private bool _dataSet;

		private Opcode _opcode;

		private byte[] _rawData;

		internal Opcode Opcode => _opcode;

		public string Data
		{
			get
			{
				setData();
				return _data;
			}
		}

		public bool IsBinary => _opcode == Opcode.Binary;

		public bool IsPing => _opcode == Opcode.Ping;

		public bool IsText => _opcode == Opcode.Text;

		public byte[] RawData
		{
			get
			{
				setData();
				return _rawData;
			}
		}

		internal MessageEventArgs(WebSocketFrame frame)
		{
			_opcode = frame.Opcode;
			_rawData = frame.PayloadData.ApplicationData;
		}

		internal MessageEventArgs(Opcode opcode, byte[] rawData)
		{
			if ((ulong)rawData.LongLength > PayloadData.MaxLength)
			{
				throw new WebSocketException(CloseStatusCode.TooBig);
			}
			_opcode = opcode;
			_rawData = rawData;
		}

		private void setData()
		{
			if (_dataSet)
			{
				return;
			}
			if (_opcode == Opcode.Binary)
			{
				_dataSet = true;
				return;
			}
			if (_rawData.TryGetUTF8DecodedString(out var s))
			{
				_data = s;
			}
			_dataSet = true;
		}
	}
	public class CloseEventArgs : EventArgs
	{
		private bool _clean;

		private PayloadData _payloadData;

		public ushort Code => _payloadData.Code;

		public string Reason => _payloadData.Reason;

		public bool WasClean => _clean;

		internal CloseEventArgs(PayloadData payloadData, bool clean)
		{
			_payloadData = payloadData;
			_clean = clean;
		}

		internal CloseEventArgs(ushort code, string reason, bool clean)
		{
			_payloadData = new PayloadData(code, reason);
			_clean = clean;
		}
	}
	public enum ByteOrder
	{
		Little,
		Big
	}
	public class ErrorEventArgs : EventArgs
	{
		private Exception _exception;

		private string _message;

		public Exception Exception => _exception;

		public string Message => _message;

		internal ErrorEventArgs(string message)
			: this(message, null)
		{
		}

		internal ErrorEventArgs(string message, Exception exception)
		{
			_message = message;
			_exception = exception;
		}
	}
	public class WebSocket : IDisposable
	{
		private AuthenticationChallenge _authChallenge;

		private string _base64Key;

		private bool _client;

		private Action _closeContext;

		private CompressionMethod _compression;

		private WebSocketContext _context;

		private WebSocketSharp.Net.CookieCollection _cookies;

		private WebSocketSharp.Net.NetworkCredential _credentials;

		private bool _emitOnPing;

		private bool _enableRedirection;

		private string _extensions;

		private bool _extensionsRequested;

		private object _forMessageEventQueue;

		private object _forPing;

		private object _forSend;

		private object _forState;

		private MemoryStream _fragmentsBuffer;

		private bool _fragmentsCompressed;

		private Opcode _fragmentsOpcode;

		private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

		private Func<WebSocketContext, string> _handshakeRequestChecker;

		private bool _ignoreExtensions;

		private bool _inContinuation;

		private volatile bool _inMessage;

		private volatile Logger _logger;

		private static readonly int _maxRetryCountForConnect;

		private Action<MessageEventArgs> _message;

		private Queue<MessageEventArgs> _messageEventQueue;

		private uint _nonceCount;

		private string _origin;

		private ManualResetEvent _pongReceived;

		private bool _preAuth;

		private string _protocol;

		private string[] _protocols;

		private bool _protocolsRequested;

		private WebSocketSharp.Net.NetworkCredential _proxyCredentials;

		private Uri _proxyUri;

		private volatile WebSocketState _readyState;

		private ManualResetEvent _receivingExited;

		private int _retryCountForConnect;

		private bool _secure;

		private ClientSslConfiguration _sslConfig;

		private Stream _stream;

		private TcpClient _tcpClient;

		private Uri _uri;

		private const string _version = "13";

		private TimeSpan _waitTime;

		internal static readonly byte[] EmptyBytes;

		internal static readonly int FragmentLength;

		internal static readonly RandomNumberGenerator RandomNumber;

		internal WebSocketSharp.Net.CookieCollection CookieCollection => _cookies;

		internal Func<WebSocketContext, string> CustomHandshakeRequestChecker
		{
			get
			{
				return _handshakeRequestChecker;
			}
			set
			{
				_handshakeRequestChecker = value;
			}
		}

		internal bool HasMessage
		{
			get
			{
				lock (_forMessageEventQueue)
				{
					return _messageEventQueue.Count > 0;
				}
			}
		}

		internal bool IgnoreExtensions
		{
			get
			{
				return _ignoreExtensions;
			}
			set
			{
				_ignoreExtensions = value;
			}
		}

		internal bool IsConnected => _readyState == WebSocketState.Open || _readyState == WebSocketState.Closing;

		public CompressionMethod Compression
		{
			get
			{
				return _compression;
			}
			set
			{
				string text = null;
				if (!_client)
				{
					text = "This instance is not a client.";
					throw new InvalidOperationException(text);
				}
				if (!canSet(out text))
				{
					_logger.Warn(text);
					return;
				}
				lock (_forState)
				{
					if (!canSet(out text))
					{
						_logger.Warn(text);
					}
					else
					{
						_compression = value;
					}
				}
			}
		}

		public IEnumerable<WebSocketSharp.Net.Cookie> Cookies
		{
			get
			{
				lock (_cookies.SyncRoot)
				{
					foreach (WebSocketSharp.Net.Cookie cookie in _cookies)
					{
						yield return cookie;
					}
				}
			}
		}

		public WebSocketSharp.Net.NetworkCredential Credentials => _credentials;

		public bool EmitOnPing
		{
			get
			{
				return _emitOnPing;
			}
			set
			{
				_emitOnPing = value;
			}
		}

		public bool EnableRedirection
		{
			get
			{
				return _enableRedirection;
			}
			set
			{
				string text = null;
				if (!_client)
				{
					text = "This instance is not a client.";
					throw new InvalidOperationException(text);
				}
				if (!canSet(out text))
				{
					_logger.Warn(text);
					return;
				}
				lock (_forState)
				{
					if (!canSet(out text))
					{
						_logger.Warn(text);
					}
					else
					{
						_enableRedirection = value;
					}
				}
			}
		}

		public string Extensions => _extensions ?? string.Empty;

		public bool IsAlive => ping(EmptyBytes);

		public bool IsSecure => _secure;

		public Logger Log
		{
			get
			{
				return _logger;
			}
			internal set
			{
				_logger = value;
			}
		}

		public string Origin
		{
			get
			{
				return _origin;
			}
			set
			{
				string text = null;
				if (!_client)
				{
					text = "This instance is not a client.";
					throw new InvalidOperationException(text);
				}
				if (!value.IsNullOrEmpty())
				{
					if (!Uri.TryCreate(value, UriKind.Absolute, out Uri result))
					{
						text = "Not an absolute URI string.";
						throw new ArgumentException(text, "value");
					}
					if (result.Segments.Length > 1)
					{
						text = "It includes the path segments.";
						throw new ArgumentException(text, "value");
					}
				}
				if (!canSet(out text))
				{
					_logger.Warn(text);
					return;
				}
				lock (_forState)
				{
					if (!canSet(out text))
					{
						_logger.Warn(text);
						return;
					}
					_origin = ((!value.IsNullOrEmpty()) ? value.TrimEnd(new char[1] { '/' }) : value);
				}
			}
		}

		public string Protocol
		{
			get
			{
				return _protocol ?? string.Empty;
			}
			internal set
			{
				_protocol = value;
			}
		}

		public WebSocketState ReadyState => _readyState;

		public ClientSslConfiguration SslConfiguration
		{
			get
			{
				if (!_client)
				{
					string text = "This instance is not a client.";
					throw new InvalidOperationException(text);
				}
				if (!_secure)
				{
					string text2 = "This instance does not use a secure connection.";
					throw new InvalidOperationException(text2);
				}
				return getSslConfiguration();
			}
		}

		public Uri Url => _client ? _uri : _context.RequestUri;

		public TimeSpan WaitTime
		{
			get
			{
				return _waitTime;
			}
			set
			{
				if (value <= TimeSpan.Zero)
				{
					throw new ArgumentOutOfRangeException("value", "Zero or less.");
				}
				if (!canSet(out var text))
				{
					_logger.Warn(text);
					return;
				}
				lock (_forState)
				{
					if (!canSet(out text))
					{
						_logger.Warn(text);
					}
					else
					{
						_waitTime = value;
					}
				}
			}
		}

		public event EventHandler<CloseEventArgs> OnClose;

		public event EventHandler<ErrorEventArgs> OnError;

		public event EventHandler<MessageEventArgs> OnMessage;

		public event EventHandler OnOpen;

		static WebSocket()
		{
			_maxRetryCountForConnect = 10;
			EmptyBytes = new byte[0];
			FragmentLength = 1016;
			RandomNumber = new RNGCryptoServiceProvider();
		}

		internal WebSocket(HttpListenerWebSocketContext context, string protocol)
		{
			_context = context;
			_protocol = protocol;
			_closeContext = context.Close;
			_logger = context.Log;
			_message = messages;
			_secure = context.IsSecureConnection;
			_stream = context.Stream;
			_waitTime = TimeSpan.FromSeconds(1.0);
			init();
		}

		internal WebSocket(TcpListenerWebSocketContext context, string protocol)
		{
			_context = context;
			_protocol = protocol;
			_closeContext = context.Close;
			_logger = context.Log;
			_message = messages;
			_secure = context.IsSecureConnection;
			_stream = context.Stream;
			_waitTime = TimeSpan.FromSeconds(1.0);
			init();
		}

		public WebSocket(string url, params string[] protocols)
		{
			if (url == null)
			{
				throw new ArgumentNullException("url");
			}
			if (url.Length == 0)
			{
				throw new ArgumentException("An empty string.", "url");
			}
			if (!url.TryCreateWebSocketUri(out _uri, out var text))
			{
				throw new ArgumentException(text, "url");
			}
			if (protocols != null && protocols.Length != 0)
			{
				if (!checkProtocols(protocols, out text))
				{
					throw new ArgumentException(text, "protocols");
				}
				_protocols = protocols;
			}
			_base64Key = CreateBase64Key();
			_client = true;
			_logger = new Logger();
			_message = messagec;
			_secure = _uri.Scheme == "wss";
			_waitTime = TimeSpan.FromSeconds(5.0);
			init();
		}

		private bool accept()
		{
			if (_readyState == WebSocketState.Open)
			{
				string text = "The handshake request has already been accepted.";
				_logger.Warn(text);
				return false;
			}
			lock (_forState)
			{
				if (_readyState == WebSocketState.Open)
				{
					string text2 = "The handshake request has already been accepted.";
					_logger.Warn(text2);
					return false;
				}
				if (_readyState == WebSocketState.Closing)
				{
					string text3 = "The close process has set in.";
					_logger.Error(text3);
					text3 = "An interruption has occurred while attempting to accept.";
					error(text3, null);
					return false;
				}
				if (_readyState == WebSocketState.Closed)
				{
					string text4 = "The connection has been closed.";
					_logger.Error(text4);
					text4 = "An interruption has occurred while attempting to accept.";
					error(text4, null);
					return false;
				}
				try
				{
					if (!acceptHandshake())
					{
						return false;
					}
				}
				catch (Exception ex)
				{
					_logger.Fatal(ex.Message);
					_logger.Debug(ex.ToString());
					string text5 = "An exception has occurred while attempting to accept.";
					fatal(text5, ex);
					return false;
				}
				_readyState = WebSocketState.Open;
				return true;
			}
		}

		private bool acceptHandshake()
		{
			_logger.Debug($"A handshake request from {_context.UserEndPoint}:\n{_context}");
			if (!checkHandshakeRequest(_context, out var text))
			{
				_logger.Error(text);
				refuseHandshake(CloseStatusCode.ProtocolError, "A handshake error has occurred while attempting to accept.");
				return false;
			}
			if (!customCheckHandshakeRequest(_context, out text))
			{
				_logger.Error(text);
				refuseHandshake(CloseStatusCode.PolicyViolation, "A handshake error has occurred while attempting to accept.");
				return false;
			}
			_base64Key = _context.Headers["Sec-WebSocket-Key"];
			if (_protocol != null)
			{
				IEnumerable<string> secWebSocketProtocols = _context.SecWebSocketProtocols;
				processSecWebSocketProtocolClientHeader(secWebSocketProtocols);
			}
			if (!_ignoreExtensions)
			{
				string value = _context.Headers["Sec-WebSocket-Extensions"];
				processSecWebSocketExtensionsClientHeader(value);
			}
			return sendHttpResponse(createHandshakeResponse());
		}

		private bool canSet(out string message)
		{
			message = null;
			if (_readyState == WebSocketState.Open)
			{
				message = "The connection has already been established.";
				return false;
			}
			if (_readyState == WebSocketState.Closing)
			{
				message = "The connection is closing.";
				return false;
			}
			return true;
		}

		private bool checkHandshakeRequest(WebSocketContext context, out string message)
		{
			message = null;
			if (!context.IsWebSocketRequest)
			{
				message = "Not a handshake request.";
				return false;
			}
			if (context.RequestUri == null)
			{
				message = "It specifies an invalid Request-URI.";
				return false;
			}
			NameValueCollection headers = context.Headers;
			string text = headers["Sec-WebSocket-Key"];
			if (text == null)
			{
				message = "It includes no Sec-WebSocket-Key header.";
				return false;
			}
			if (text.Length == 0)
			{
				message = "It includes an invalid Sec-WebSocket-Key header.";
				return false;
			}
			string text2 = headers["Sec-WebSocket-Version"];
			if (text2 == null)
			{
				message = "It includes no Sec-WebSocket-Version header.";
				return false;
			}
			if (text2 != "13")
			{
				message = "It includes an invalid Sec-WebSocket-Version header.";
				return false;
			}
			string text3 = headers["Sec-WebSocket-Protocol"];
			if (text3 != null && text3.Length == 0)
			{
				message = "It includes an invalid Sec-WebSocket-Protocol header.";
				return false;
			}
			if (!_ignoreExtensions)
			{
				string text4 = headers["Sec-WebSocket-Extensions"];
				if (text4 != null && text4.Length == 0)
				{
					message = "It includes an invalid Sec-WebSocket-Extensions header.";
					return false;
				}
			}
			return true;
		}

		private bool checkHandshakeResponse(HttpResponse response, out string message)
		{
			message = null;
			if (response.IsRedirect)
			{
				message = "Indicates the redirection.";
				return false;
			}
			if (response.IsUnauthorized)
			{
				message = "Requires the authentication.";
				return false;
			}
			if (!response.IsWebSocketResponse)
			{
				message = "Not a WebSocket handshake response.";
				return false;
			}
			NameValueCollection headers = response.Headers;
			if (!validateSecWebSocketAcceptHeader(headers["Sec-WebSocket-Accept"]))
			{
				message = "Includes no Sec-WebSocket-Accept header, or it has an invalid value.";
				return false;
			}
			if (!validateSecWebSocketProtocolServerHeader(headers["Sec-WebSocket-Protocol"]))
			{
				message = "Includes no Sec-WebSocket-Protocol header, or it has an invalid value.";
				return false;
			}
			if (!validateSecWebSocketExtensionsServerHeader(headers["Sec-WebSocket-Extensions"]))
			{
				message = "Includes an invalid Sec-WebSocket-Extensions header.";
				return false;
			}
			if (!validateSecWebSocketVersionServerHeader(headers["Sec-WebSocket-Version"]))
			{
				message = "Includes an invalid Sec-WebSocket-Version header.";
				return false;
			}
			return true;
		}

		private static bool checkProtocols(string[] protocols, out string message)
		{
			message = null;
			Func<string, bool> condition = (string protocol) => protocol.IsNullOrEmpty() || !protocol.IsToken();
			if (protocols.Contains(condition))
			{
				message = "It contains a value that is not a token.";
				return false;
			}
			if (protocols.ContainsTwice())
			{
				message = "It contains a value twice.";
				return false;
			}
			return true;
		}

		private bool checkReceivedFrame(WebSocketFrame frame, out string message)
		{
			message = null;
			bool isMasked = frame.IsMasked;
			if (_client && isMasked)
			{
				message = "A frame from the server is masked.";
				return false;
			}
			if (!_client && !isMasked)
			{
				message = "A frame from a client is not masked.";
				return false;
			}
			if (_inContinuation && frame.IsData)
			{
				message = "A data frame has been received while receiving continuation frames.";
				return false;
			}
			if (frame.IsCompressed && _compression == CompressionMethod.None)
			{
				message = "A compressed frame has been received without any agreement for it.";
				return false;
			}
			if (frame.Rsv2 == Rsv.On)
			{
				message = "The RSV2 of a frame is non-zero without any negotiation for it.";
				return false;
			}
			if (frame.Rsv3 == Rsv.On)
			{
				message = "The RSV3 of a frame is non-zero without any negotiation for it.";
				return false;
			}
			return true;
		}

		private void close(ushort code, string reason)
		{
			if (_readyState == WebSocketState.Closing)
			{
				_logger.Info("The closing is already in progress.");
				return;
			}
			if (_readyState == WebSocketState.Closed)
			{
				_logger.Info("The connection has already been closed.");
				return;
			}
			if (code == 1005)
			{
				close(PayloadData.Empty, send: true, receive: true, received: false);
				return;
			}
			bool receive = !code.IsReserved();
			close(new PayloadData(code, reason), receive, receive, received: false);
		}

		private void close(PayloadData payloadData, bool send, bool receive, bool received)
		{
			lock (_forState)
			{
				if (_readyState == WebSocketState.Closing)
				{
					_logger.Info("The closing is already in progress.");
					return;
				}
				if (_readyState == WebSocketState.Closed)
				{
					_logger.Info("The connection has already been closed.");
					return;
				}
				send = send && _readyState == WebSocketState.Open;
				receive = send && receive;
				_readyState = WebSocketState.Closing;
			}
			_logger.Trace("Begin closing the connection.");
			bool clean = closeHandshake(payloadData, send, receive, received);
			releaseResources();
			_logger.Trace("End closing the connection.");
			_readyState = WebSocketState.Closed;
			CloseEventArgs e = new CloseEventArgs(payloadData, clean);
			try
			{
				this.OnClose.Emit(this, e);
			}
			catch (Exception ex)
			{
				_logger.Error(ex.Message);
				_logger.Debug(ex.ToString());
			}
		}

		private void closeAsync(ushort code, string reason)
		{
			if (_readyState == WebSocketState.Closing)
			{
				_logger.Info("The closing is already in progress.");
				return;
			}
			if (_readyState == WebSocketState.Closed)
			{
				_logger.Info("The connection has already been closed.");
				return;
			}
			if (code == 1005)
			{
				closeAsync(PayloadData.Empty, send: true, receive: true, received: false);
				return;
			}
			bool receive = !code.IsReserved();
			closeAsync(new PayloadData(code, reason), receive, receive, received: false);
		}

		private void closeAsync(PayloadData payloadData, bool send, bool receive, bool received)
		{
			Action<PayloadData, bool, bool, bool> closer = close;
			closer.BeginInvoke(payloadData, send, receive, received, delegate(IAsyncResult ar)
			{
				closer.EndInvoke(ar);
			}, null);
		}

		private bool closeHandshake(byte[] frameAsBytes, bool receive, bool received)
		{
			bool flag = frameAsBytes != null && sendBytes(frameAsBytes);
			if (!received && flag && receive && _receivingExited != null)
			{
				received = _receivingExited.WaitOne(_waitTime);
			}
			bool flag2 = flag && received;
			_logger.Debug($"Was clean?: {flag2}\n  sent: {flag}\n  received: {received}");
			return flag2;
		}

		private bool closeHandshake(PayloadData payloadData, bool send, bool receive, bool received)
		{
			bool flag = false;
			if (send)
			{
				WebSocketFrame webSocketFrame = WebSocketFrame.CreateCloseFrame(payloadData, _client);
				flag = sendBytes(webSocketFrame.ToArray());
				if (_client)
				{
					webSocketFrame.Unmask();
				}
			}
			if (!received && flag && receive && _receivingExited != null)
			{
				received = _receivingExited.WaitOne(_waitTime);
			}
			bool flag2 = flag && received;
			_logger.Debug($"Was clean?: {flag2}\n  sent: {flag}\n  received: {received}");
			return flag2;
		}

		private bool connect()
		{
			if (_readyState == WebSocketState.Open)
			{
				string text = "The connection has already been established.";
				_logger.Warn(text);
				return false;
			}
			lock (_forState)
			{
				if (_readyState == WebSocketState.Open)
				{
					string text2 = "The connection has already been established.";
					_logger.Warn(text2);
					return false;
				}
				if (_readyState == WebSocketState.Closing)
				{
					string text3 = "The close process has set in.";
					_logger.Error(text3);
					text3 = "An interruption has occurred while attempting to connect.";
					error(text3, null);
					return false;
				}
				if (_retryCountForConnect > _maxRetryCountForConnect)
				{
					string text4 = "An opportunity for reconnecting has been lost.";
					_logger.Error(text4);
					text4 = "An interruption has occurred while attempting to connect.";
					error(text4, null);
					return false;
				}
				_readyState = WebSocketState.Connecting;
				try
				{
					doHandshake();
				}
				catch (Exception ex)
				{
					_retryCountForConnect++;
					_logger.Fatal(ex.Message);
					_logger.Debug(ex.ToString());
					string text5 = "An exception has occurred while attempting to connect.";
					fatal(text5, ex);
					return false;
				}
				_retryCountForConnect = 1;
				_readyState = WebSocketState.Open;
				return true;
			}
		}

		private string createExtensions()
		{
			StringBuilder stringBuilder = new StringBuilder(80);
			if (_compression != 0)
			{
				string arg = _compression.ToExtensionString("server_no_context_takeover", "client_no_context_takeover");
				stringBuilder.AppendFormat("{0}, ", arg);
			}
			int length = stringBuilder.Length;
			if (length > 2)
			{
				stringBuilder.Length = length - 2;
				return stringBuilder.ToString();
			}
			return null;
		}

		private HttpResponse createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode code)
		{
			HttpResponse httpResponse = HttpResponse.CreateCloseResponse(code);
			httpResponse.Headers["Sec-WebSocket-Version"] = "13";
			return httpResponse;
		}

		private HttpRequest createHandshakeRequest()
		{
			HttpRequest httpRequest = HttpRequest.CreateWebSocketRequest(_uri);
			NameValueCollection headers = httpRequest.Headers;
			if (!_origin.IsNullOrEmpty())
			{
				headers["Origin"] = _origin;
			}
			headers["Sec-WebSocket-Key"] = _base64Key;
			_protocolsRequested = _protocols != null;
			if (_protocolsRequested)
			{
				headers["Sec-WebSocket-Protocol"] = _protocols.ToString(", ");
			}
			_extensionsRequested = _compression != CompressionMethod.None;
			if (_extensionsRequested)
			{
				headers["Sec-WebSocket-Extensions"] = createExtensions();
			}
			headers["Sec-WebSocket-Version"] = "13";
			AuthenticationResponse authenticationResponse = null;
			if (_authChallenge != null && _credentials != null)
			{
				authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount);
				_nonceCount = authenticationResponse.NonceCount;
			}
			else if (_preAuth)
			{
				authenticationResponse = new AuthenticationResponse(_credentials);
			}
			if (authenticationResponse != null)
			{
				headers["Authorization"] = authenticationResponse.ToString();
			}
			if (_cookies.Count > 0)
			{
				httpRequest.SetCookies(_cookies);
			}
			return httpRequest;
		}

		private HttpResponse createHandshakeResponse()
		{
			HttpResponse httpResponse = HttpResponse.CreateWebSocketResponse();
			NameValueCollection headers = httpResponse.Headers;
			headers["Sec-WebSocket-Accept"] = CreateResponseKey(_base64Key);
			if (_protocol != null)
			{
				headers["Sec-WebSocket-Protocol"] = _protocol;
			}
			if (_extensions != null)
			{
				headers["Sec-WebSocket-Extensions"] = _extensions;
			}
			if (_cookies.Count > 0)
			{
				httpResponse.SetCookies(_cookies);
			}
			return httpResponse;
		}

		private bool customCheckHandshakeRequest(WebSocketContext context, out string message)
		{
			message = null;
			if (_handshakeRequestChecker == null)
			{
				return true;
			}
			message = _handshakeRequestChecker(context);
			return message == null;
		}

		private MessageEventArgs dequeueFromMessageEventQueue()
		{
			lock (_forMessageEventQueue)
			{
				return (_messageEventQueue.Count > 0) ? _messageEventQueue.Dequeue() : null;
			}
		}

		private void doHandshake()
		{
			setClientStream();
			HttpResponse httpResponse = sendHandshakeRequest();
			if (!checkHandshakeResponse(httpResponse, out var text))
			{
				throw new WebSocketException(CloseStatusCode.ProtocolError, text);
			}
			if (_protocolsRequested)
			{
				_protocol = httpResponse.Headers["Sec-WebSocket-Protocol"];
			}
			if (_extensionsRequested)
			{
				processSecWebSocketExtensionsServerHeader(httpResponse.Headers["Sec-WebSocket-Extensions"]);
			}
			processCookies(httpResponse.Cookies);
		}

		private void enqueueToMessageEventQueue(MessageEventArgs e)
		{
			lock (_forMessageEventQueue)
			{
				_messageEventQueue.Enqueue(e);
			}
		}

		private void error(string message, Exception exception)
		{
			try
			{
				this.OnError.Emit(this, new ErrorEventArgs(message, exception));
			}
			catch (Exception ex)
			{
				_logger.Error(ex.Message);
				_logger.Debug(ex.ToString());
			}
		}

		private void fatal(string message, Exception exception)
		{
			CloseStatusCode code = ((exception is WebSocketException) ? ((WebSocketException)exception).Code : CloseStatusCode.Abnormal);
			fatal(message, (ushort)code);
		}

		private void fatal(string message, ushort code)
		{
			PayloadData payloadData = new PayloadData(code, message);
			close(payloadData, !code.IsReserved(), receive: false, received: false);
		}

		private void fatal(string message, CloseStatusCode code)
		{
			fatal(message, (ushort)code);
		}

		private ClientSslConfiguration getSslConfiguration()
		{
			if (_sslConfig == null)
			{
				_sslConfig = new ClientSslConfiguration(_uri.DnsSafeHost);
			}
			return _sslConfig;
		}

		private void init()
		{
			_compression = CompressionMethod.None;
			_cookies = new WebSocketSharp.Net.CookieCollection();
			_forPing = new object();
			_forSend = new object();
			_forState = new object();
			_messageEventQueue = new Queue<MessageEventArgs>();
			_forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot;
			_readyState = WebSocketState.Connecting;
		}

		private void message()
		{
			MessageEventArgs obj = null;
			lock (_forMessageEventQueue)
			{
				if (_inMessage || _messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
				{
					return;
				}
				_inMessage = true;
				obj = _messageEventQueue.Dequeue();
			}
			_message(obj);
		}

		private void messagec(MessageEventArgs e)
		{
			while (true)
			{
				try
				{
					this.OnMessage.Emit(this, e);
				}
				catch (Exception ex)
				{
					_logger.Error(ex.ToString());
					error("An error has occurred during an OnMessage event.", ex);
				}
				lock (_forMessageEventQueue)
				{
					if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
					{
						_inMessage = false;
						break;
					}
					e = _messageEventQueue.Dequeue();
				}
				bool flag = true;
			}
		}

		private void messages(MessageEventArgs e)
		{
			try
			{
				this.OnMessage.Emit(this, e);
			}
			catch (Exception ex)
			{
				_logger.Error(ex.ToString());
				error("An error has occurred during an OnMessage event.", ex);
			}
			lock (_forMessageEventQueue)
			{
				if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
				{
					_inMessage = false;
					return;
				}
				e = _messageEventQueue.Dequeue();
			}
			ThreadPool.QueueUserWorkItem(delegate
			{
				messages(e);
			});
		}

		private void open()
		{
			_inMessage = true;
			startReceiving();
			try
			{
				this.OnOpen.Emit(this, EventArgs.Empty);
			}
			catch (Exception ex)
			{
				_logger.Error(ex.ToString());
				error("An error has occurred during the OnOpen event.", ex);
			}
			MessageEventArgs obj = null;
			lock (_forMessageEventQueue)
			{
				if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open)
				{
					_inMessage = false;
					return;
				}
				obj = _messageEventQueue.Dequeue();
			}
			_message.BeginInvoke(obj, delegate(IAsyncResult ar)
			{
				_message.EndInvoke(ar);
			}, null);
		}

		private bool ping(byte[] data)
		{
			if (_readyState != WebSocketState.Open)
			{
				return false;
			}
			ManualResetEvent pongReceived = _pongReceived;
			if (pongReceived == null)
			{
				return false;
			}
			lock (_forPing)
			{
				try
				{
					pongReceived.Reset();
					if (!send(Fin.Final, Opcode.Ping, data, compressed: false))
					{
						return false;
					}
					return pongReceived.WaitOne(_waitTime);
				}
				catch (ObjectDisposedException)
				{
					return false;
				}
			}
		}

		private bool processCloseFrame(WebSocketFrame frame)
		{
			PayloadData payloadData = frame.PayloadData;
			close(payloadData, !payloadData.HasReservedCode, receive: false, received: true);
			return false;
		}

		private void processCookies(WebSocketSharp.Net.CookieCollection cookies)
		{
			if (cookies.Count != 0)
			{
				_cookies.SetOrRemove(cookies);
			}
		}

		private bool processDataFrame(WebSocketFrame frame)
		{
			enqueueToMessageEventQueue(frame.IsCompressed ? new MessageEventArgs(frame.Opcode, frame.PayloadData.ApplicationData.Decompress(_compression)) : new MessageEventArgs(frame));
			return true;
		}

		private bool processFragmentFrame(WebSocketFrame frame)
		{
			if (!_inContinuation)
			{
				if (frame.IsContinuation)
				{
					return true;
				}
				_fragmentsOpcode = frame.Opcode;
				_fragmentsCompressed = frame.IsCompressed;
				_fragmentsBuffer = new MemoryStream();
				_inContinuation = true;
			}
			_fragmentsBuffer.WriteBytes(frame.PayloadData.ApplicationData, 1024);
			if (frame.IsFinal)
			{
				using (_fragmentsBuffer)
				{
					byte[] rawData = (_fragmentsCompressed ? _fragmentsBuffer.DecompressToArray(_compression) : _fragmentsBuffer.ToArray());
					enqueueToMessageEventQueue(new MessageEventArgs(_fragmentsOpcode, rawData));
				}
				_fragmentsBuffer = null;
				_inContinuation = false;
			}
			return true;
		}

		private bool processPingFrame(WebSocketFrame frame)
		{
			_logger.Trace("A ping was received.");
			WebSocketFrame webSocketFrame = WebSocketFrame.CreatePongFrame(frame.PayloadData, _client);
			lock (_forState)
			{
				if (_readyState != WebSocketState.Open)
				{
					_logger.Error("The connection is closing.");
					return true;
				}
				if (!sendBytes(webSocketFrame.ToArray()))
				{
					return false;
				}
			}
			_logger.Trace("A pong to this ping has been sent.");
			if (_emitOnPing)
			{
				if (_client)
				{
					webSocketFrame.Unmask();
				}
				enqueueToMessageEventQueue(new MessageEventArgs(frame));
			}
			return true;
		}

		private bool processPongFrame(WebSocketFrame frame)
		{
			_logger.Trace("A pong was received.");
			try
			{
				_pongReceived.Set();
			}
			catch (NullReferenceException ex)
			{
				_logger.Error(ex.Message);
				_logger.Debug(ex.ToString());
				return false;
			}
			catch (ObjectDisposedException ex2)
			{
				_logger.Error(ex2.Message);
				_logger.Debug(ex2.ToString());
				return false;
			}
			_logger.Trace("It has been signaled.");
			return true;
		}

		private bool processReceivedFrame(WebSocketFrame frame)
		{
			if (!checkReceivedFrame(frame, out var text))
			{
				throw new WebSocketException(CloseStatusCode.ProtocolError, text);
			}
			frame.Unmask();
			return frame.IsFragment ? processFragmentFrame(frame) : (frame.IsData ? processDataFrame(frame) : (frame.IsPing ? processPingFrame(frame) : (frame.IsPong ? processPongFrame(frame) : (frame.IsClose ? processCloseFrame(frame) : processUnsupportedFrame(frame)))));
		}

		private void processSecWebSocketExtensionsClientHeader(string value)
		{
			if (value == null)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder(80);
			bool flag = false;
			foreach (string item in value.SplitHeaderValue(','))
			{
				string text = item.Trim();
				if (text.Length != 0 && !flag && text.IsCompressionExtension(CompressionMethod.Deflate))
				{
					_compression = CompressionMethod.Deflate;
					stringBuilder.AppendFormat("{0}, ", _compression.ToExtensionString("client_no_context_takeover", "server_no_context_takeover"));
					flag = true;
				}
			}
			int length = stringBuilder.Length;
			if (length > 2)
			{
				stringBuilder.Length = length - 2;
				_extensions = stringBuilder.ToString();
			}
		}

		private void processSecWebSocketExtensionsServerHeader(string value)
		{
			if (value == null)
			{
				_compression = CompressionMethod.None;
			}
			else
			{
				_extensions = value;
			}
		}

		private void processSecWebSocketProtocolClientHeader(IEnumerable<string> values)
		{
			if (!values.Contains((string val) => val == _protocol))
			{
				_protocol = null;
			}
		}

		private bool processUnsupportedFrame(WebSocketFrame frame)
		{
			_logger.Fatal("An unsupported frame:" + frame.PrintToString(dumped: false));
			fatal("There is no way to handle it.", CloseStatusCode.PolicyViolation);
			return false;
		}

		private void refuseHandshake(CloseStatusCode code, string reason)
		{
			_readyState = WebSocketState.Closing;
			HttpResponse response = createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest);
			sendHttpResponse(response);
			releaseServerResources();
			_readyState = WebSocketState.Closed;
			CloseEventArgs e = new CloseEventArgs((ushort)code, reason, clean: false);
			try
			{
				this.OnClose.Emit(this, e);
			}
			catch (Exception ex)
			{
				_logger.Error(ex.Message);
				_logger.Debug(ex.ToString());
			}
		}

		private void releaseClientResources()
		{
			if (_stream != null)
			{
				_stream.Dispose();
				_stream = null;
			}
			if (_tcpClient != null)
			{
				_tcpClient.Close();
				_tcpClient = null;
			}
		}

		private void releaseCommonResources()
		{
			if (_fragmentsBuffer != null)
			{
				_fragmentsBuffer.Dispose();
				_fragmentsBuffer = null;
				_inContinuation = false;
			}
			if (_pongReceived != null)
			{
				_pongReceived.Close();
				_pongReceived = null;
			}
			if (_receivingExited != null)
			{
				_receivingExited.Close();
				_receivingExited = null;
			}
		}

		private void releaseResources()
		{
			if (_client)
			{
				releaseClientResources();
			}
			else
			{
				releaseServerResources();
			}
			releaseCommonResources();
		}

		private void releaseServerResources()
		{
			if (_closeContext != null)
			{
				_closeContext();
				_closeContext = null;
				_stream = null;
				_context = null;
			}
		}

		private bool send(Opcode opcode, Stream stream)
		{
			lock (_forSend)
			{
				Stream stream2 = stream;
				bool flag = false;
				bool flag2 = false;
				try
				{
					if (_compression != 0)
					{
						stream = stream.Compress(_compression);
						flag = true;
					}
					flag2 = send(opcode, stream, flag);
					if (!flag2)
					{
						error("A send has been interrupted.", null);
					}
				}
				catch (Exception ex)
				{
					_logger.Error(ex.ToString());
					error("An error has occurred during a send.", ex);
				}
				finally
				{
					if (flag)
					{
						stream.Dispose();
					}
					stream2.Dispose();
				}
				return flag2;
			}
		}

		private bool send(Opcode opcode, Stream stream, bool compressed)
		{
			long length = stream.Length;
			if (length == 0)
			{
				return send(Fin.Final, opcode, EmptyBytes, compressed: false);
			}
			long num = length / FragmentLength;
			int num2 = (int)(length % FragmentLength);
			byte[] array = null;
			switch (num)
			{
			case 0L:
				array = new byte[num2];
				return stream.Read(array, 0, num2) == num2 && send(Fin.Final, opcode, array, compressed);
			case 1L:
				if (num2 == 0)
				{
					array = new byte[FragmentLength];
					return stream.Read(array, 0, FragmentLength) == FragmentLength && send(Fin.Final, opcode, array, compressed);
				}
				break;
			}
			array = new byte[FragmentLength];
			if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, opcode, array, compressed))
			{
				return false;
			}
			long num3 = ((num2 == 0) ? (num - 2) : (num - 1));
			for (long num4 = 0L; num4 < num3; num4++)
			{
				if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, Opcode.Cont, array, compressed: false))
				{
					return false;
				}
			}
			if (num2 == 0)
			{
				num2 = FragmentLength;
			}
			else
			{
				array = new byte[num2];
			}
			return stream.Read(array, 0, num2) == num2 && send(Fin.Final, Opcode.Cont, array, compressed: false);
		}

		private bool send(Fin fin, Opcode opcode, byte[] data, bool compressed)
		{
			lock (_forState)
			{
				if (_readyState != WebSocketState.Open)
				{
					_logger.Error("The connection is closing.");
					return false;
				}
				WebSocketFrame webSocketFrame = new WebSocketFrame(fin, opcode, data, compressed, _client);
				return sendBytes(webSocketFrame.ToArray());
			}
		}

		private void sendAsync(Opcode opcode, Stream stream, Action<bool> completed)
		{
			Func<Opcode, Stream, bool> sender = send;
			sender.BeginInvoke(opcode, stream, delegate(IAsyncResult ar)
			{
				try
				{
					bool obj = sender.EndInvoke(ar);
					if (completed != null)
					{
						completed(obj);
					}
				}
				catch (Exception ex)
				{
					_logger.Error(ex.ToString());
					error("An error has occurred during the callback for an async send.", ex);
				}
			}, null);
		}

		private bool sendBytes(byte[] bytes)
		{
			try
			{
				_stream.Write(bytes, 0, bytes.Length);
			}
			catch (Exception ex)
			{
				_logger.Error(ex.Message);
				_logger.Debug(ex.ToString());
				return false;
			}
			return true;
		}

		private HttpResponse sendHandshakeRequest()
		{
			HttpRequest httpRequest = createHandshakeRequest();
			HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000);
			if (httpResponse.IsUnauthorized)
			{
				string text = httpResponse.Headers["WWW-Authenticate"];
				_logger.Warn($"Received an authentication requirement for '{text}'.");
				if (text.IsNullOrEmpty())
				{
					_logger.Error("No authentication challenge is specified.");
					return httpResponse;
				}
				_authChallenge = AuthenticationChallenge.Parse(text);
				if (_authChallenge == null)
				{
					_logger.Error("An invalid authentication challenge is specified.");
					return httpResponse;
				}
				if (_credentials != null && (!_preAuth || _authChallenge.Scheme == WebSocketSharp.Net.AuthenticationSchemes.Digest))
				{
					if (httpResponse.HasConnectionClose)
					{
						releaseClientResources();
						setClientStream();
					}
					AuthenticationResponse authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount);
					_nonceCount = authenticationResponse.NonceCount;
					httpRequest.Headers["Authorization"] = authenticationResponse.ToString();
					httpResponse = sendHttpRequest(httpRequest, 15000);
				}
			}
			if (httpResponse.IsRedirect)
			{
				string text2 = httpResponse.Headers["Location"];
				_logger.Warn($"Received a redirection to '{text2}'.");
				if (_enableRedirection)
				{
					if (text2.IsNullOrEmpty())
					{
						_logger.Error("No url to redirect is located.");
						return httpResponse;
					}
					if (!text2.TryCreateWebSocketUri(out var result, out var text3))
					{
						_logger.Error("An invalid url to redirect is located: " + text3);
						return httpResponse;
					}
					releaseClientResources();
					_uri = result;
					_secure = result.Scheme == "wss";
					setClientStream();
					return sendHandshakeRequest();
				}
			}
			return httpResponse;
		}

		private HttpResponse sendHttpRequest(HttpRequest request, int millisecondsTimeout)
		{
			_logger.Debug("A request to the server:\n" + request.ToString());
			HttpResponse response = request.GetResponse(_stream, millisecondsTimeout);
			_logger.Debug("A response to this request:\n" + response.ToString());
			return response;
		}

		private bool sendHttpResponse(HttpResponse response)
		{
			_logger.Debug($"A response to {_context.UserEndPoint}:\n{response}");
			return sendBytes(response.ToByteArray());
		}

		private void sendProxyConnectRequest()
		{
			HttpRequest httpRequest = HttpRequest.CreateConnectRequest(_uri);
			HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000);
			if (httpResponse.IsProxyAuthenticationRequired)
			{
				string text = httpResponse.Headers["Proxy-Authenticate"];
				_logger.Warn($"Received a proxy authentication requirement for '{text}'.");
				if (text.IsNullOrEmpty())
				{
					throw new WebSocketException("No proxy authentication challenge is specified.");
				}
				AuthenticationChallenge authenticationChallenge = AuthenticationChallenge.Parse(text);
				if (authenticationChallenge == null)
				{
					throw new WebSocketException("An invalid proxy authentication challenge is specified.");
				}
				if (_proxyCredentials != null)
				{
					if (httpResponse.HasConnectionClose)
					{
						releaseClientResources();
						_tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port);
						_stream = _tcpClient.GetStream();
					}
					AuthenticationResponse authenticationResponse = new AuthenticationResponse(authenticationChallenge, _proxyCredentials, 0u);
					httpRequest.Headers["Proxy-Authorization"] = authenticationResponse.ToString();
					httpResponse = sendHttpRequest(httpRequest, 15000);
				}
				if (httpResponse.IsProxyAuthenticationRequired)
				{
					throw new WebSocketException("A proxy authentication is required.");
				}
			}
			if (httpResponse.StatusCode[0] != '2')
			{
				throw new WebSocketException("The proxy has failed a connection to the requested host and port.");
			}
		}

		private void setClientStream()
		{
			if (_proxyUri != null)
			{
				_tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port);
				_stream = _tcpClient.GetStream();
				sendProxyConnectRequest();
			}
			else
			{
				_tcpClient = new TcpClient(_uri.DnsSafeHost, _uri.Port);
				_stream = _tcpClient.GetStream();
			}
			if (_secure)
			{
				ClientSslConfiguration sslConfiguration = getSslConfiguration();
				string targetHost = sslConfiguration.TargetHost;
				if (targetHost != _uri.DnsSafeHost)
				{
					throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, "An invalid host name is specified.");
				}
				try
				{
					SslStream sslStream = new SslStream(_stream, leaveInnerStreamOpen: false, sslConfiguration.ServerCertificateValidationCallback, sslConfiguration.ClientCertificateSelectionCallback);
					sslStream.AuthenticateAsClient(targetHost, sslConfiguration.ClientCertificates, sslConfiguration.EnabledSslProtocols, sslConfiguration.CheckCertificateRevocation);
					_stream = sslStream;
				}
				catch (Exception innerException)
				{
					throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, innerException);
				}
			}
		}

		private void startReceiving()
		{
			if (_messageEventQueue.Count > 0)
			{
				_messageEventQueue.Clear();
			}
			_pongReceived = new ManualResetEvent(initialState: false);
			_receivingExited = new ManualResetEvent(initialState: false);
			Action receive = null;
			receive = delegate
			{
				WebSocketFrame.ReadFrameAsync(_stream, unmask: false, delegate(WebSocketFrame frame)
				{
					if (!processReceivedFrame(frame) || _readyState == WebSocketState.Closed)
					{
						_receivingExited?.Set();
					}
					else
					{
						receive();
						if (!_inMessage && HasMessage && _readyState == WebSocketState.Open)
						{
							message();
						}
					}
				}, delegate(Exception ex)
				{
					_logger.Fatal(ex.ToString());
					fatal("An exception has occurred while receiving.", ex);
				});
			};
			receive();
		}

		private bool validateSecWebSocketAcceptHeader(string value)
		{
			return value != null && value == CreateResponseKey(_base64Key);
		}

		private bool validateSecWebSocketExtensionsServerHeader(string value)
		{
			if (value == null)
			{
				return true;
			}
			if (value.Length == 0)
			{
				return false;
			}
			if (!_extensionsRequested)
			{
				return false;
			}
			bool flag = _compression != CompressionMethod.None;
			foreach (string item in value.SplitHeaderValue(','))
			{
				string text = item.Trim();
				if (flag && text.IsCompressionExtension(_compression))
				{
					if (!text.Contains("server_no_context_takeover"))
					{
						_logger.Error("The server hasn't sent back 'server_no_context_takeover'.");
						return false;
					}
					if (!text.Contains("client_no_context_takeover"))
					{
						_logger.Warn("The server hasn't sent back 'client_no_context_takeover'.");
					}
					string method = _compression.ToExtensionString();
					if (text.SplitHeaderValue(';').Contains(delegate(string t)
					{
						t = t.Trim();
						return t != method && t != "server_no_context_takeover" && t != "client_no_context_takeover";
					}))
					{
						return false;
					}
					continue;
				}
				return false;
			}
			return true;
		}

		private bool validateSecWebSocketProtocolServerHeader(string value)
		{
			if (value == null)
			{
				return !_protocolsRequested;
			}
			if (value.Length == 0)
			{
				return false;
			}
			return _protocolsRequested && _protocols.Contains((string p) => p == value);
		}

		private bool validateSecWebSocketVersionServerHeader(string value)
		{
			return value == null || value == "13";
		}

		internal void Close(HttpResponse response)
		{
			_readyState = WebSocketState.Closing;
			sendHttpResponse(response);
			releaseServerResources();
			_readyState = WebSocketState.Closed;
		}

		internal void Close(WebSocketSharp.Net.HttpStatusCode code)
		{
			Close(createHandshakeFailureResponse(code));
		}

		internal void Close(PayloadData payloadData, byte[] frameAsBytes)
		{
			lock (_forState)
			{
				if (_readyState == WebSocketState.Closing)
				{
					_logger.Info("The closing is already in progress.");
					return;
				}
				if (_readyState == WebSocketState.Closed)
				{
					_logger.Info("The connection has already been closed.");
					return;
				}
				_readyState = WebSocketState.Closing;
			}
			_logger.Trace("Begin closing the connection.");
			bool flag = frameAsBytes != null && sendBytes(frameAsBytes);
			bool flag2 = flag && _receivingExited != null && _receivingExited.WaitOne(_waitTime);
			bool flag3 = flag && flag2;
			_logger.Debug($"Was clean?: {flag3}\n  sent: {flag}\n  received: {flag2}");
			releaseServerResources();
			releaseCommonResources();
			_logger.Trace("End closing the connection.");
			_readyState = WebSocketState.Closed;
			CloseEventArgs e = new CloseEventArgs(payloadData, flag3);
			try
			{
				this.OnClose.Emit(this, e);
			}
			catch (Exception ex)
			{
				_logger.Error(ex.Message);
				_logger.Debug(ex.ToString());
			}
		}

		internal static string CreateBase64Key()
		{
			byte[] array = new byte[16];
			RandomNumber.GetBytes(array);
			return Convert.ToBase64String(array);
		}

		internal static string CreateResponseKey(string base64Key)
		{
			StringBuilder stringBuilder = new StringBuilder(base64Key, 64);
			stringBuilder.Append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
			SHA1 sHA = new SHA1CryptoServiceProvider();
			byte[] inArray = sHA.ComputeHash(stringBuilder.ToString().GetUTF8EncodedBytes());
			return Convert.ToBase64String(inArray);
		}

		internal void InternalAccept()
		{
			try
			{
				if (!acceptHandshake())
				{
					return;
				}
			}
			catch (Exception ex)
			{
				_logger.Fatal(ex.Message);
				_logger.Debug(ex.ToString());
				string text = "An exception has occurred while attempting to accept.";
				fatal(text, ex);
				return;
			}
			_readyState = WebSocketState.Open;
			open();
		}

		internal bool Ping(byte[] frameAsBytes, TimeSpan timeout)
		{
			if (_readyState != WebSocketState.Open)
			{
				return false;
			}
			ManualResetEvent pongReceived = _pongReceived;
			if (pongReceived == null)
			{
				return false;
			}
			lock (_forPing)
			{
				try
				{
					pongReceived.Reset();
					lock (_forState)
					{
						if (_readyState != WebSocketState.Open)
						{
							return false;
						}
						if (!sendBytes(frameAsBytes))
						{
							return false;
						}
					}
					return pongReceived.WaitOne(timeout);
				}
				catch (ObjectDisposedException)
				{
					return false;
				}
			}
		}

		internal void Send(Opcode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache)
		{
			lock (_forSend)
			{
				lock (_forState)
				{
					if (_readyState != WebSocketState.Open)
					{
						_logger.Error("The connection is closing.");
						return;
					}
					if (!cache.TryGetValue(_compression, out var value))
					{
						value = new WebSocketFrame(Fin.Final, opcode, data.Compress(_compression), _compression != CompressionMethod.None, mask: false).ToArray();
						cache.Add(_compression, value);
					}
					sendBytes(value);
				}
			}
		}

		internal void Send(Opcode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache)
		{
			lock (_forSend)
			{
				if (!cache.TryGetValue(_compression, out var value))
				{
					value = stream.Compress(_compression);
					cache.Add(_compression, value);
				}
				else
				{
					value.Position = 0L;
				}
				send(opcode, value, _compression != CompressionMethod.None);
			}
		}

		public void Accept()
		{
			if (_client)
			{
				string text = "This instance is a client.";
				throw new InvalidOperationException(text);
			}
			if (_readyState == WebSocketState.Closing)
			{
				string text2 = "The close process is in progress.";
				throw new InvalidOperationException(text2);
			}
			if (_readyState == WebSocketState.Closed)
			{
				string text3 = "The connection has already been closed.";
				throw new InvalidOperationException(text3);
			}
			if (accept())
			{
				open();
			}
		}

		public void AcceptAsync()
		{
			if (_client)
			{
				string text = "This instance is a client.";
				throw new InvalidOperationException(text);
			}
			if (_readyState == WebSocketState.Closing)
			{
				string text2 = "The close process is in progress.";
				throw new InvalidOperationException(text2);
			}
			if (_readyState == WebSocketState.Closed)
			{
				string text3 = "The connection has already been closed.";
				throw new InvalidOperationException(text3);
			}
			Func<bool> acceptor = accept;
			acceptor.BeginInvoke(delegate(IAsyncResult ar)
			{
				if (acceptor.EndInvoke(ar))
				{
					open();
				}
			}, null);
		}

		public void Close()
		{
			close(1005, string.Empty);
		}

		public void Close(ushort code)
		{
			if (!code.IsCloseStatusCode())
			{
				string text = "Less than 1000 or greater than 4999.";
				throw new ArgumentOutOfRangeException("code", text);
			}
			if (_client && code == 1011)
			{
				string text2 = "1011 cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			if (!_client && code == 1010)
			{
				string text3 = "1010 cannot be used.";
				throw new ArgumentException(text3, "code");
			}
			close(code, string.Empty);
		}

		public void Close(CloseStatusCode code)
		{
			if (_client && code == CloseStatusCode.ServerError)
			{
				string text = "ServerError cannot be used.";
				throw new ArgumentException(text, "code");
			}
			if (!_client && code == CloseStatusCode.MandatoryExtension)
			{
				string text2 = "MandatoryExtension cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			close((ushort)code, string.Empty);
		}

		public void Close(ushort code, string reason)
		{
			if (!code.IsCloseStatusCode())
			{
				string text = "Less than 1000 or greater than 4999.";
				throw new ArgumentOutOfRangeException("code", text);
			}
			if (_client && code == 1011)
			{
				string text2 = "1011 cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			if (!_client && code == 1010)
			{
				string text3 = "1010 cannot be used.";
				throw new ArgumentException(text3, "code");
			}
			if (reason.IsNullOrEmpty())
			{
				close(code, string.Empty);
				return;
			}
			if (code == 1005)
			{
				string text4 = "1005 cannot be used.";
				throw new ArgumentException(text4, "code");
			}
			if (!reason.TryGetUTF8EncodedBytes(out var bytes))
			{
				string text5 = "It could not be UTF-8-encoded.";
				throw new ArgumentException(text5, "reason");
			}
			if (bytes.Length > 123)
			{
				string text6 = "Its size is greater than 123 bytes.";
				throw new ArgumentOutOfRangeException("reason", text6);
			}
			close(code, reason);
		}

		public void Close(CloseStatusCode code, string reason)
		{
			if (_client && code == CloseStatusCode.ServerError)
			{
				string text = "ServerError cannot be used.";
				throw new ArgumentException(text, "code");
			}
			if (!_client && code == CloseStatusCode.MandatoryExtension)
			{
				string text2 = "MandatoryExtension cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			if (reason.IsNullOrEmpty())
			{
				close((ushort)code, string.Empty);
				return;
			}
			if (code == CloseStatusCode.NoStatus)
			{
				string text3 = "NoStatus cannot be used.";
				throw new ArgumentException(text3, "code");
			}
			if (!reason.TryGetUTF8EncodedBytes(out var bytes))
			{
				string text4 = "It could not be UTF-8-encoded.";
				throw new ArgumentException(text4, "reason");
			}
			if (bytes.Length > 123)
			{
				string text5 = "Its size is greater than 123 bytes.";
				throw new ArgumentOutOfRangeException("reason", text5);
			}
			close((ushort)code, reason);
		}

		public void CloseAsync()
		{
			closeAsync(1005, string.Empty);
		}

		public void CloseAsync(ushort code)
		{
			if (!code.IsCloseStatusCode())
			{
				string text = "Less than 1000 or greater than 4999.";
				throw new ArgumentOutOfRangeException("code", text);
			}
			if (_client && code == 1011)
			{
				string text2 = "1011 cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			if (!_client && code == 1010)
			{
				string text3 = "1010 cannot be used.";
				throw new ArgumentException(text3, "code");
			}
			closeAsync(code, string.Empty);
		}

		public void CloseAsync(CloseStatusCode code)
		{
			if (_client && code == CloseStatusCode.ServerError)
			{
				string text = "ServerError cannot be used.";
				throw new ArgumentException(text, "code");
			}
			if (!_client && code == CloseStatusCode.MandatoryExtension)
			{
				string text2 = "MandatoryExtension cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			closeAsync((ushort)code, string.Empty);
		}

		public void CloseAsync(ushort code, string reason)
		{
			if (!code.IsCloseStatusCode())
			{
				string text = "Less than 1000 or greater than 4999.";
				throw new ArgumentOutOfRangeException("code", text);
			}
			if (_client && code == 1011)
			{
				string text2 = "1011 cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			if (!_client && code == 1010)
			{
				string text3 = "1010 cannot be used.";
				throw new ArgumentException(text3, "code");
			}
			if (reason.IsNullOrEmpty())
			{
				closeAsync(code, string.Empty);
				return;
			}
			if (code == 1005)
			{
				string text4 = "1005 cannot be used.";
				throw new ArgumentException(text4, "code");
			}
			if (!reason.TryGetUTF8EncodedBytes(out var bytes))
			{
				string text5 = "It could not be UTF-8-encoded.";
				throw new ArgumentException(text5, "reason");
			}
			if (bytes.Length > 123)
			{
				string text6 = "Its size is greater than 123 bytes.";
				throw new ArgumentOutOfRangeException("reason", text6);
			}
			closeAsync(code, reason);
		}

		public void CloseAsync(CloseStatusCode code, string reason)
		{
			if (_client && code == CloseStatusCode.ServerError)
			{
				string text = "ServerError cannot be used.";
				throw new ArgumentException(text, "code");
			}
			if (!_client && code == CloseStatusCode.MandatoryExtension)
			{
				string text2 = "MandatoryExtension cannot be used.";
				throw new ArgumentException(text2, "code");
			}
			if (reason.IsNullOrEmpty())
			{
				closeAsync((ushort)code, string.Empty);
				return;
			}
			if (code == CloseStatusCode.NoStatus)
			{
				string text3 = "NoStatus cannot be used.";
				throw new ArgumentException(text3, "code");
			}
			if (!reason.TryGetUTF8EncodedBytes(out var bytes))
			{
				string text4 = "It could not be UTF-8-encoded.";
				throw new ArgumentException(text4, "reason");
			}
			if (bytes.Length > 123)
			{
				string text5 = "Its size is greater than 123 bytes.";
				throw new ArgumentOutOfRangeException("reason", text5);
			}
			closeAsync((ushort)code, reason);
		}

		public void Connect()
		{
			if (!_client)
			{
				string text = "This instance is not a client.";
				throw new InvalidOperationException(text);
			}
			if (_readyState == WebSocketState.Closing)
			{
				string text2 = "The close process is in progress.";
				throw new InvalidOperationException(text2);
			}
			if (_retryCountForConnect > _maxRetryCountForConnect)
			{
				string text3 = "A series of reconnecting has failed.";
				throw new InvalidOperationException(text3);
			}
			if (connect())
			{
				open();
			}
		}

		public void ConnectAsync()
		{
			if (!_client)
			{
				string text = "This instance is not a client.";
				throw new InvalidOperationException(text);
			}
			if (_readyState == WebSocketState.Closing)
			{
				string text2 = "The close process is in progress.";
				throw new InvalidOperationException(text2);
			}
			if (_retryCountForConnect > _maxRetryCountForConnect)
			{
				string text3 = "A series of reconnecting has failed.";
				throw new InvalidOperationException(text3);
			}
			Func<bool> connector = connect;
			connector.BeginInvoke(delegate(IAsyncResult ar)
			{
				if (connector.EndInvoke(ar))
				{
					open();
				}
			}, null);
		}

		public bool Ping()
		{
			return ping(EmptyBytes);
		}

		public bool Ping(string message)
		{
			if (message.IsNullOrEmpty())
			{
				return ping(EmptyBytes);
			}
			if (!message.TryGetUTF8EncodedBytes(out var bytes))
			{
				string text = "It could not be UTF-8-encoded.";
				throw new ArgumentException(text, "message");
			}
			if (bytes.Length > 125)
			{
				string text2 = "Its size is greater than 125 bytes.";
				throw new ArgumentOutOfRangeException("message", text2);
			}
			return ping(bytes);
		}

		public void Send(byte[] data)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			send(Opcode.Binary, new MemoryStream(data));
		}

		public void Send(FileInfo fileInfo)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (fileInfo == null)
			{
				throw new ArgumentNullException("fileInfo");
			}
			if (!fileInfo.Exists)
			{
				string text2 = "The file does not exist.";
				throw new ArgumentException(text2, "fileInfo");
			}
			if (!fileInfo.TryOpenRead(out var fileStream))
			{
				string text3 = "The file could not be opened.";
				throw new ArgumentException(text3, "fileInfo");
			}
			send(Opcode.Binary, fileStream);
		}

		public void Send(string data)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			if (!data.TryGetUTF8EncodedBytes(out var bytes))
			{
				string text2 = "It could not be UTF-8-encoded.";
				throw new ArgumentException(text2, "data");
			}
			send(Opcode.Text, new MemoryStream(bytes));
		}

		public void Send(Stream stream, int length)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			if (!stream.CanRead)
			{
				string text2 = "It cannot be read.";
				throw new ArgumentException(text2, "stream");
			}
			if (length < 1)
			{
				string text3 = "Less than 1.";
				throw new ArgumentException(text3, "length");
			}
			byte[] array = stream.ReadBytes(length);
			int num = array.Length;
			if (num == 0)
			{
				string text4 = "No data could be read from it.";
				throw new ArgumentException(text4, "stream");
			}
			if (num < length)
			{
				_logger.Warn($"Only {num} byte(s) of data could be read from the stream.");
			}
			send(Opcode.Binary, new MemoryStream(array));
		}

		public void SendAsync(byte[] data, Action<bool> completed)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			sendAsync(Opcode.Binary, new MemoryStream(data), completed);
		}

		public void SendAsync(FileInfo fileInfo, Action<bool> completed)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (fileInfo == null)
			{
				throw new ArgumentNullException("fileInfo");
			}
			if (!fileInfo.Exists)
			{
				string text2 = "The file does not exist.";
				throw new ArgumentException(text2, "fileInfo");
			}
			if (!fileInfo.TryOpenRead(out var fileStream))
			{
				string text3 = "The file could not be opened.";
				throw new ArgumentException(text3, "fileInfo");
			}
			sendAsync(Opcode.Binary, fileStream, completed);
		}

		public void SendAsync(string data, Action<bool> completed)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (data == null)
			{
				throw new ArgumentNullException("data");
			}
			if (!data.TryGetUTF8EncodedBytes(out var bytes))
			{
				string text2 = "It could not be UTF-8-encoded.";
				throw new ArgumentException(text2, "data");
			}
			sendAsync(Opcode.Text, new MemoryStream(bytes), completed);
		}

		public void SendAsync(Stream stream, int length, Action<bool> completed)
		{
			if (_readyState != WebSocketState.Open)
			{
				string text = "The current state of the connection is not Open.";
				throw new InvalidOperationException(text);
			}
			if (stream == null)
			{
				throw new ArgumentNullException("stream");
			}
			if (!stream.CanRead)
			{
				string text2 = "It cannot be read.";
				throw new ArgumentException(text2, "stream");
			}
			if (length < 1)
			{
				string text3 = "Less than 1.";
				throw new ArgumentException(text3, "length");
			}
			byte[] array = stream.ReadBytes(length);
			int num = array.Length;
			if (num == 0)
			{
				string text4 = "No data could be read from it.";
				throw new ArgumentException(text4, "stream");
			}
			if (num < length)
			{
				_logger.Warn($"Only {num} byte(s) of data could be read from the stream.");
			}
			sendAsync(Opcode.Binary, new MemoryStream(array), completed);
		}

		public void SetCookie(WebSocketSharp.Net.Cookie cookie)
		{
			string text = null;
			if (!_client)
			{
				text = "This instance is not a client.";
				throw new InvalidOperationException(text);
			}
			if (cookie == null)
			{
				throw new ArgumentNullException("cookie");
			}
			if (!canSet(out text))
			{
				_logger.Warn(text);
				return;
			}
			lock (_forState)
			{
				if (!canSet(out text))
				{
					_logger.Warn(text);
					return;
				}
				lock (_cookies.SyncRoot)
				{
					_cookies.SetOrRemove(cookie);
				}
			}
		}

		public void SetCredentials(string username, string password, bool preAuth)
		{
			string text = null;
			if (!_client)
			{
				text = "This instance is not a client.";
				throw new InvalidOperationException(text);
			}
			if (!username.IsNullOrEmpty() && (Ext.Contains(username, ':') || !username.IsText()))
			{
				text = "It contains an invalid character.";
				throw new ArgumentException(text, "username");
			}
			if (!password.IsNullOrEmpty() && !password.IsText())
			{
				text = "It contains an invalid character.";
				throw new ArgumentException(text, "password");
			}
			if (!canSet(out text))
			{
				_logger.Warn(text);
				return;
			}
			lock (_forState)
			{
				if (!canSet(out text))
				{
					_logger.Warn(text);
				}
				else if (username.IsNullOrEmpty())
				{
					_credentials = null;
					_preAuth = false;
				}
				else
				{
					_credentials = new WebSocketSharp.Net.NetworkCredential(username, password, _uri.PathAndQuery);
					_preAuth = preAuth;
				}
			}
		}

		public void SetProxy(string url, string username, string password)
		{
			string text = null;
			if (!_client)
			{
				text = "This instance is not a client.";
				throw new InvalidOperationException(text);
			}
			Uri result = null;
			if (!url.IsNullOrEmpty())
			{
				if (!Uri.TryCreate(url, UriKind.Absolute, out result))
				{
					text = "Not an absolute URI string.";
					throw new ArgumentException(text, "url");
				}
				if (result.Scheme != "http")
				{
					text = "The scheme part is not http.";
					throw new ArgumentException(text, "url");
				}
				if (result.Segments.Length > 1)
				{
					text = "It includes the path segments.";
					throw new ArgumentException(text, "url");
				}
			}
			if (!username.IsNullOrEmpty() && (Ext.Contains(username, ':') || !username.IsText()))
			{
				text = "It contains an invalid character.";
				throw new ArgumentException(text, "username");
			}
			if (!password.IsNullOrEmpty() && !password.IsText())
			{
				text = "It contains an invalid character.";
				throw new ArgumentException(text, "password");
			}
			if (!canSet(out text))
			{
				_logger.Warn(text);
				return;
			}
			lock (_forState)
			{
				if (!canSet(out text))
				{
					_logger.Warn(text);