Decompiled source of Archipelago v2.0.7

Archipelago.MultiClient.Net.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Archipelago.MultiClient.Net.Cache;
using Archipelago.MultiClient.Net.ConcurrentCollection;
using Archipelago.MultiClient.Net.Converters;
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 © 2023")]
[assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")]
[assembly: AssemblyFileVersion("5.0.5.0")]
[assembly: AssemblyInformationalVersion("5.0.5")]
[assembly: AssemblyProduct("Archipelago.MultiClient.Net")]
[assembly: AssemblyTitle("Archipelago.MultiClient.Net")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")]
[assembly: AssemblyVersion("5.0.5.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);
}
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 class ArchipelagoSession
	{
		private const int ArchipelagoConnectionTimeoutInSeconds = 4;

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

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

		public IArchipelagoSocketHelper Socket { get; }

		public ReceivedItemsHelper Items { get; }

		public LocationCheckHelper Locations { get; }

		public PlayerHelper Players { get; }

		public DataStorageHelper DataStorage { get; }

		public ConnectionInfoHelper ConnectionInfo { get; }

		public RoomStateHelper RoomState { get; }

		public MessageLogHelper MessageLog { get; }

		internal ArchipelagoSession(IArchipelagoSocketHelper socket, ReceivedItemsHelper items, LocationCheckHelper locations, PlayerHelper players, RoomStateHelper roomState, ConnectionInfoHelper connectionInfo, DataStorageHelper dataStorage, MessageLogHelper messageLog)
		{
			Socket = socket;
			Items = items;
			Locations = locations;
			Players = players;
			RoomState = roomState;
			ConnectionInfo = connectionInfo;
			DataStorage = dataStorage;
			MessageLog = messageLog;
			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);
				}
				return;
			}
			if (packet is ConnectedPacket && RoomState.Version != null && RoomState.Version >= new Version(0, 3, 8))
			{
				LogUsedVersion();
			}
			loginResultTask.TrySetResult(LoginResult.FromPacket(packet));
		}

		private void LogUsedVersion()
		{
			try
			{
				string fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
				Socket.SendPacketAsync(new SetPacket
				{
					Key = ".NetUsedVersions",
					DefaultValue = (JToken)(object)JObject.FromObject((object)new Dictionary<string, bool>()),
					Operations = new OperationSpecification[1] { Operation.Update(new Dictionary<string, bool> { 
					{
						ConnectionInfo.Game + ":" + fileVersion + ":NET45",
						true
					} }) }
				});
			}
			catch
			{
			}
		}

		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 = new TaskCompletionSource<LoginResult>();
				loginResultTask.SetResult(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.SetResult(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, 4, 0)),
				ItemsHandling = ConnectionInfo.ItemsHandlingFlags,
				RequestSlotData = requestSlotData
			};
		}
	}
	public static class ArchipelagoSessionFactory
	{
		public static ArchipelagoSession CreateSession(Uri uri)
		{
			ArchipelagoSocketHelper socket = new ArchipelagoSocketHelper(uri);
			DataPackageCache dataPackageCache = new DataPackageCache(socket);
			LocationCheckHelper locationCheckHelper = new LocationCheckHelper(socket, dataPackageCache);
			ReceivedItemsHelper items = new ReceivedItemsHelper(socket, locationCheckHelper, dataPackageCache);
			ConnectionInfoHelper connectionInfoHelper = new ConnectionInfoHelper(socket);
			PlayerHelper players = new PlayerHelper(socket, connectionInfoHelper);
			RoomStateHelper roomState = new RoomStateHelper(socket, locationCheckHelper);
			DataStorageHelper dataStorage = new DataStorageHelper(socket, connectionInfoHelper);
			MessageLogHelper messageLog = new MessageLogHelper(socket, items, locationCheckHelper, players, connectionInfoHelper);
			return new ArchipelagoSession(socket, items, locationCheckHelper, players, roomState, connectionInfoHelper, dataStorage, messageLog);
		}

		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}.", 
			};
		}
	}
}
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(StringEnumConverter))]
		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 DataPackagePacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.DataPackage;

		[JsonProperty("data")]
		public 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 bool CreateAsHint { get; set; }
	}
	public class PrintJsonPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.PrintJSON;

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

		[JsonProperty("type")]
		[JsonConverter(typeof(StringEnumConverter))]
		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("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; }

		[Obsolete("use DataPackageChecksums instead")]
		[JsonProperty("datapackage_versions")]
		public Dictionary<string, int> DataPackageVersions { 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; }

		public Guid? Reference { get; set; }
	}
	public class SetReplyPacket : ArchipelagoPacketBase
	{
		public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.SetReply;

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

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

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

		[JsonProperty("original_value")]
		public JToken OriginalValue { get; set; }

		[JsonProperty("operation")]
		public string Operation { get; set; }

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

		public Guid? Reference { 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;
	}
}
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;

		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();
			Operations.Add(new OperationSpecification
			{
				OperationType = operationType,
				Value = value
			});
			Callbacks = source.Callbacks;
		}

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

		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, 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, JToken b)
		{
			return new DataStorageElement(a, OperationType.Mul, b);
		}

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

		public static DataStorageElement operator ^(DataStorageElement a, JToken b)
		{
			return new DataStorageElement(a, OperationType.Pow, 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, decimal b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(-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, float b)
		{
			return new DataStorageElement(a, OperationType.Add, JToken.FromObject((object)(0f - 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, decimal b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1m / 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, float b)
		{
			return new DataStorageElement(a, OperationType.Mul, JToken.FromObject((object)(1.0 / (double)b)));
		}

		[Obsolete("Use + Operation.Min() instead")]
		public static DataStorageElement operator >>(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Min, JToken.op_Implicit(b));
		}

		[Obsolete("Use + Operation.Max() instead")]
		public static DataStorageElement operator <<(DataStorageElement a, int b)
		{
			return new DataStorageElement(a, OperationType.Max, JToken.op_Implicit(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 decimal(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<decimal>(e);
		}

		public static implicit operator decimal?(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<decimal?>(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 float(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<float>(e);
		}

		public static implicit operator float?(DataStorageElement e)
		{
			return RetrieveAndReturnDecimalValue<float?>(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 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Invalid comparison between Unknown and I4
			//IL_00d7: 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_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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;
				}
			}
			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; }
	}
	public class JsonMessagePart
	{
		[JsonProperty("type")]
		[JsonConverter(typeof(StringEnumConverter), new object[] { typeof(SnakeCaseNamingStrategy) })]
		public JsonMessagePartType? Type { get; set; }

		[JsonProperty("color")]
		[JsonConverter(typeof(StringEnumConverter), 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; }
	}
	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(StringEnumConverter), 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(JToken i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = i
			};
		}

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

		public static OperationSpecification Remove(JToken value)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Remove,
				Value = 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 class Bitwise
	{
		public static OperationSpecification Xor(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Xor,
				Value = JToken.op_Implicit(i)
			};
		}

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

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

		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
			};
		}
	}
}
namespace Archipelago.MultiClient.Net.MessageLog.Parts
{
	public class EntranceMessagePart : MessagePart
	{
		internal EntranceMessagePart(JsonMessagePart messagePart)
			: base(MessagePartType.Entrance, messagePart, Color.Blue)
		{
			base.Text = messagePart.Text;
		}
	}
	public class ItemMessagePart : MessagePart
	{
		public ItemFlags Flags { get; }

		public long ItemId { get; }

		internal ItemMessagePart(IReceivedItemsHelper items, JsonMessagePart part)
			: base(MessagePartType.Item, part)
		{
			Flags = part.Flags.GetValueOrDefault();
			base.Color = GetColor(Flags);
			JsonMessagePartType? type = part.Type;
			if (type.HasValue)
			{
				switch (type.GetValueOrDefault())
				{
				case JsonMessagePartType.ItemId:
					ItemId = long.Parse(part.Text);
					base.Text = items.GetItemName(ItemId) ?? $"Item: {ItemId}";
					break;
				case JsonMessagePartType.ItemName:
					ItemId = 0L;
					base.Text = part.Text;
					break;
				}
			}
		}

		private static Color GetColor(ItemFlags flags)
		{
			if (HasFlag(flags, ItemFlags.Advancement))
			{
				return Color.Plum;
			}
			if (HasFlag(flags, ItemFlags.NeverExclude))
			{
				return Color.SlateBlue;
			}
			if (HasFlag(flags, ItemFlags.Trap))
			{
				return Color.Salmon;
			}
			return Color.Cyan;
		}

		private static bool HasFlag(ItemFlags flags, ItemFlags flag)
		{
			return flags.HasFlag(flag);
		}
	}
	public class LocationMessagePart : MessagePart
	{
		public long LocationId { get; }

		internal LocationMessagePart(ILocationCheckHelper locations, JsonMessagePart part)
			: base(MessagePartType.Location, part, Color.Green)
		{
			JsonMessagePartType? type = part.Type;
			if (type.HasValue)
			{
				switch (type.GetValueOrDefault())
				{
				case JsonMessagePartType.LocationId:
					LocationId = long.Parse(part.Text);
					base.Text = locations.GetLocationNameFromId(LocationId) ?? $"Location: {LocationId}";
					break;
				case JsonMessagePartType.PlayerName:
					LocationId = 0L;
					base.Text = part.Text;
					break;
				}
			}
		}
	}
	public class MessagePart
	{
		public string Text { get; internal set; }

		public MessagePartType Type { get; internal set; }

		public Color Color { get; internal set; }

		public bool IsBackgroundColor { get; internal set; }

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

		private static Color GetColor(JsonMessagePartColor color)
		{
			switch (color)
			{
			case JsonMessagePartColor.Red:
			case JsonMessagePartColor.RedBg:
				return Color.Red;
			case JsonMessagePartColor.Green:
			case JsonMessagePartColor.GreenBg:
				return Color.Green;
			case JsonMessagePartColor.Yellow:
			case JsonMessagePartColor.YellowBg:
				return Color.Yellow;
			case JsonMessagePartColor.Blue:
			case JsonMessagePartColor.BlueBg:
				return Color.Blue;
			case JsonMessagePartColor.Magenta:
			case JsonMessagePartColor.MagentaBg:
				return Color.Magenta;
			case JsonMessagePartColor.Cyan:
			case JsonMessagePartColor.CyanBg:
				return Color.Cyan;
			case JsonMessagePartColor.Black:
			case JsonMessagePartColor.BlackBg:
				return Color.Black;
			case JsonMessagePartColor.White:
			case JsonMessagePartColor.WhiteBg:
				return Color.White;
			default:
				return Color.White;
			}
		}

		public override string ToString()
		{
			return Text;
		}
	}
	public enum MessagePartType
	{
		Text,
		Player,
		Item,
		Location,
		Entrance
	}
	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.Color = GetColor(IsActivePlayer);
		}

		private static Color GetColor(bool isActivePlayer)
		{
			if (isActivePlayer)
			{
				return Color.Magenta;
			}
			return Color.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, IConnectionInfoProvider connectionInfo, int team, int slot, string message)
			: base(parts, players, connectionInfo, team, slot)
		{
			Message = message;
		}
	}
	public class CollectLogMessage : PlayerSpecificLogMessage
	{
		internal CollectLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, 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, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, team, slot)
		{
		}
	}
	public class HintItemSendLogMessage : ItemSendLogMessage
	{
		public bool IsFound { get; }

		internal HintItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int receiver, int sender, NetworkItem item, bool found)
			: base(parts, players, connectionInfo, receiver, sender, item)
		{
			IsFound = found;
		}
	}
	public class ItemCheatLogMessage : ItemSendLogMessage
	{
		internal ItemCheatLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot, NetworkItem item)
			: base(parts, players, connectionInfo, slot, 0, item, team)
		{
		}
	}
	public class ItemSendLogMessage : LogMessage
	{
		[Obsolete("Use Receiver.Slot instead")]
		public int ReceivingPlayerSlot { get; }

		[Obsolete("Use Sender.Slot instead")]
		public int SendingPlayerSlot { get; }

		public PlayerInfo Receiver { get; }

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer { get; }

		public bool IsSenderTheActivePlayer { get; }

		public bool IsRelatedToActivePlayer { get; }

		public NetworkItem Item { get; }

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

		internal ItemSendLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int receiver, int sender, NetworkItem item, int team)
			: base(parts)
		{
			ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> players2 = players.Players;
			ReceivingPlayerSlot = receiver;
			SendingPlayerSlot = sender;
			IsReceiverTheActivePlayer = connectionInfo.Team == team && connectionInfo.Slot == receiver;
			IsSenderTheActivePlayer = connectionInfo.Team == team && connectionInfo.Slot == sender;
			Receiver = ((players2.Count > team && players2[team].Count > receiver) ? players2[team][receiver] : new PlayerInfo());
			Sender = ((players2.Count > team && players2[team].Count > sender) ? players2[team][sender] : new PlayerInfo());
			IsRelatedToActivePlayer = IsReceiverTheActivePlayer || IsSenderTheActivePlayer || Receiver.IsSharingGroupWith(connectionInfo.Team, connectionInfo.Slot) || Sender.IsSharingGroupWith(connectionInfo.Team, connectionInfo.Slot);
			Item = item;
		}
	}
	public class JoinLogMessage : PlayerSpecificLogMessage
	{
		public string[] Tags { get; }

		internal JoinLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot, string[] tags)
			: base(parts, players, connectionInfo, team, slot)
		{
			Tags = tags;
		}
	}
	public class LeaveLogMessage : PlayerSpecificLogMessage
	{
		internal LeaveLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, 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
	{
		public PlayerInfo Player { get; }

		public bool IsActivePlayer { get; }

		public bool IsRelatedToActivePlayer { get; }

		internal PlayerSpecificLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts)
		{
			ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> players2 = players.Players;
			IsActivePlayer = connectionInfo.Team == team && connectionInfo.Slot == slot;
			Player = ((players2.Count > team && players2[team].Count > slot) ? players2[team][slot] : new PlayerInfo());
			IsRelatedToActivePlayer = IsActivePlayer || Player.IsSharingGroupWith(connectionInfo.Team, connectionInfo.Slot);
		}
	}
	public class ReleaseLogMessage : PlayerSpecificLogMessage
	{
		internal ReleaseLogMessage(MessagePart[] parts, IPlayerHelper players, IConnectionInfoProvider connectionInfo, int team, int slot)
			: base(parts, players, connectionInfo, 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, IConnectionInfoProvider connectionInfo, int team, int slot, string[] tags)
			: base(parts, players, connectionInfo, team, slot)
		{
			Tags = tags;
		}
	}
	public class TutorialLogMessage : LogMessage
	{
		internal TutorialLogMessage(MessagePart[] parts)
			: base(parts)
		{
		}
	}
}
namespace Archipelago.MultiClient.Net.Helpers
{
	public class ArchipelagoSocketHelper : IArchipelagoSocketHelper
	{
		private static readonly ArchipelagoPacketConverter Converter = new ArchipelagoPacketConverter();

		private const int ReceiveChunkSize = 1024;

		private const int SendChunkSize = 1024;

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

		internal ClientWebSocket webSocket;

		public Uri Uri { get; }

		public bool Connected
		{
			get
			{
				if (webSocket.State != WebSocketState.Open)
				{
					return webSocket.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 ArchipelagoSocketHelper(Uri hostUri)
		{
			Uri = hostUri;
			webSocket = new ClientWebSocket();
			SecurityProtocolType securityProtocolType = SecurityProtocolType.Tls13;
			ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | securityProtocolType;
		}

		public async Task ConnectAsync()
		{
			await ConnectToProvidedUri(Uri);
			if (this.SocketOpened != null)
			{
				this.SocketOpened();
			}
			Task.Run((Func<Task?>)PollingLoop);
			Task.Run((Func<Task?>)SendLoop);
		}

		private async Task ConnectToProvidedUri(Uri uri)
		{
			if (uri.Scheme != "unspecified")
			{
				await webSocket.ConnectAsync(uri, CancellationToken.None);
				return;
			}
			try
			{
				await ConnectToProvidedUri(uri.AsWss());
				if (webSocket.State == WebSocketState.Open)
				{
					return;
				}
			}
			catch
			{
				webSocket = new ClientWebSocket();
			}
			await ConnectToProvidedUri(uri.AsWs());
		}

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

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

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

		public async Task DisconnectAsync()
		{
			await webSocket.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 (webSocket.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 / 1024.0);
			for (int i = 0; i < messagesCount; i++)
			{
				int num = 1024 * i;
				int num2 = 1024;
				bool endOfMessage = i + 1 == messagesCount;
				if (num2 * (i + 1) > messageBuffer.Length)
				{
					num2 = messageBuffer.Length - num;
				}
				await webSocket.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 = JsonConvert.DeserializeObject<List<ArchipelagoPacketBase>>(message, (JsonConverter[])(object)new JsonConverter[1] { Converter });
				if (list == null)
				{
					return;
				}
				foreach (ArchipelagoPacketBase item in list)
				{
					this.PacketReceived(item);
				}
			}
			catch (Exception e)
			{
				OnError(e);
			}
		}

		private 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);
			}
		}
	}
	internal 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();
				}
			}
			else
			{
				Team = connectedPacket.Team;
				Slot = connectedPacket.Slot;
			}
		}

		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 class DataStorageHelper
	{
		public delegate void DataStorageUpdatedHandler(JToken originalValue, JToken newValue);

		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)
		{
			if (!(packet is RetrievedPacket retrievedPacket))
			{
				if (packet is SetReplyPacket setReplyPacket)
				{
					if (setReplyPacket.Reference.HasValue && operationSpecificCallbacks.TryGetValue(setReplyPacket.Reference.Value, out var value))
					{
						value(setReplyPacket.OriginalValue, setReplyPacket.Value);
						operationSpecificCallbacks.Remove(setReplyPacket.Reference.Value);
					}
					if (onValueChangedEventHandlers.TryGetValue(setReplyPacket.Key, out var value2))
					{
						value2(setReplyPacket.OriginalValue, setReplyPacket.Value);
					}
				}
				return;
			}
			foreach (KeyValuePair<string, JToken> datum in retrievedPacket.Data)
			{
				if (asyncRetrievalTasks.TryGetValue(datum.Key, out var value3))
				{
					value3.SetResult(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)
				});
			}
			if (e.Callbacks != null)
			{
				Guid guid = Guid.NewGuid();
				operationSpecificCallbacks[guid] = e.Callbacks;
				socket.SendPacketAsync(new SetPacket
				{
					Key = key,
					Operations = e.Operations.ToArray(),
					WantReply = true,
					Reference = guid
				});
			}
			else
			{
				socket.SendPacketAsync(new SetPacket
				{
					Key = key,
					Operations = e.Operations.ToArray()
				});
			}
		}

		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)];
		}

		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)
			{
				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 GetSlotDataElement(slot).To<Dictionary<string, object>>();
		}

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

		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 class ArchipelagoSocketHelperDelagates
	{
		public delegate void PacketReceivedHandler(ArchipelagoPacketBase packet);

		public delegate void PacketsSentHandler(ArchipelagoPacketBase[] packets);

		public delegate void ErrorReceivedHandler(Exception e, string message);

		public delegate void SocketClosedHandler(string reason);

		public delegate void SocketOpenedHandler();
	}
	public interface IArchipelagoSocketHelper
	{
		Uri Uri { get; }

		bool Connected { get; }

		event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived;

		event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent;

		event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived;

		event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed;

		event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened;

		void SendPacket(ArchipelagoPacketBase packet);

		void SendMultiplePackets(List<ArchipelagoPacketBase> packets);

		void SendMultiplePackets(params ArchipelagoPacketBase[] packets);

		Task ConnectAsync();

		Task DisconnectAsync();

		Task SendPacketAsync(ArchipelagoPacketBase packet);

		Task SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets);

		Task SendMultiplePacketsAsync(params ArchipelagoPacketBase[] packets);
	}
	public interface ILocationCheckHelper
	{
		ReadOnlyCollection<long> AllLocations { get; }

		ReadOnlyCollection<long> AllLocationsChecked { get; }

		ReadOnlyCollection<long> AllMissingLocations { get; }

		void CompleteLocationChecks(params long[] ids);

		Task CompleteLocationChecksAsync(params long[] ids);

		long GetLocationIdFromName(string game, string locationName);

		string GetLocationNameFromId(long locationId);
	}
	public class LocationCheckHelper : ILocationCheckHelper
	{
		public delegate void CheckedLocationsUpdatedHandler(ReadOnlyCollection<long> newCheckedLocations);

		private readonly IConcurrentHashSet<long> allLocations = new ConcurrentHashSet<long>();

		private readonly IConcurrentHashSet<long> locationsChecked = new ConcurrentHashSet<long>();

		private readonly IConcurrentHashSet<long> serverConfirmedChecks = new ConcurrentHashSet<long>();

		private ReadOnlyCollection<long> missingLocations = new ReadOnlyCollection<long>(new long[0]);

		private readonly IArchipelagoSocketHelper socket;

		private readonly IDataPackageCache cache;

		private bool awaitingLocationInfoPacket;

		private TaskCompletionSource<LocationInfoPacket> locationInfoPacketCallbackTask;

		private Dictionary<string, Dictionary<string, long>> gameLocationNameToIdMapping;

		private Dictionary<long, string> locationIdToNameMapping;

		public ReadOnlyCollection<long> AllLocations => allLocations.AsToReadOnlyCollection();

		public ReadOnlyCollection<long> AllLocationsChecked => locationsChecked.AsToReadOnlyCollection();

		public ReadOnlyCollection<long> AllMissingLocations => missingLocations;

		public event CheckedLocationsUpdatedHandler CheckedLocationsUpdated;

		internal LocationCheckHelper(IArchipelagoSocketHelper socket, IDataPackageCache cache)
		{
			this.socket = socket;
			this.cache = cache;
			socket.PacketReceived += Socket_PacketReceived;
		}

		private void Socket_PacketReceived(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket connectedPacket))
			{
				if (!(packet is RoomUpdatePacket roomUpdatePacket))
				{
					if (!(packet is LocationInfoPacket result))
					{
						if (packet is InvalidPacketPacket invalidPacketPacket && awaitingLocationInfoPacket && invalidPacketPacket.OriginalCmd == ArchipelagoPacketType.LocationScouts)
						{
							locationInfoPacketCallbackTask.TrySetException(new ArchipelagoServerRejectedPacketException(invalidPacketPacket.OriginalCmd, invalidPacketPacket.ErrorType, "location scout rejected by the server: " + invalidPacketPacket.ErrorText));
							awaitingLocationInfoPacket = false;
							locationInfoPacketCallbackTask = null;
						}
					}
					else if (awaitingLocationInfoPacket)
					{
						if (locationInfoPacketCallbackTask != null)
						{
							locationInfoPacketCallbackTask.SetResult(result);
						}
						awaitingLocationInfoPacket = false;
						locationInfoPacketCallbackTask = null;
					}
				}
				else
				{
					CheckLocations(roomUpdatePacket.CheckedLocations);
					if (roomUpdatePacket.CheckedLocations != null)
					{
						serverConfirmedChecks.UnionWith(roomUpdatePacket.CheckedLocations);
					}
				}
			}
			else
			{
				allLocations.UnionWith(connectedPacket.LocationsChecked);
				allLocations.UnionWith(connectedPacket.MissingChecks);
				serverConfirmedChecks.UnionWith(connectedPacket.LocationsChecked);
				missingLocations = new ReadOnlyCollection<long>(connectedPacket.MissingChecks);
				CheckLocations(connectedPacket.LocationsChecked);
			}
		}

		public void CompleteLocationChecks(params long[] ids)
		{
			CheckLocations(ids);
			LocationChecksPacket locationChecksPacket = GetLocationChecksPacket();
			if (locationChecksPacket.Locations.Any())
			{
				socket.SendPacket(locationChecksPacket);
			}
		}

		public Task CompleteLocationChecksAsync(params long[] ids)
		{
			return Task.Factory.StartNew(delegate
			{
				CheckLocations(ids);
			}).ContinueWith(delegate
			{
				if (GetLocationChecksPacket().Locations.Any())
				{
					socket.SendPacketAsync(GetLocationChecksPacket());
				}
			});
		}

		private LocationChecksPacket GetLocationChecksPacket()
		{
			return new LocationChecksPacket
			{
				Locations = locationsChecked.AsToReadOnlyCollectionExcept(serverConfirmedChecks).ToArray()
			};
		}

		public Task<LocationInfoPacket> ScoutLocationsAsync(bool createAsHint, params long[] ids)
		{
			locationInfoPacketCallbackTask = new TaskCompletionSource<LocationInfoPacket>();
			awaitingLocationInfoPacket = true;
			socket.SendPacket(new LocationScoutsPacket
			{
				Locations = ids,
				CreateAsHint = createAsHint
			});
			return locationInfoPacketCallbackTask.Task;
		}

		public Task<LocationInfoPacket> ScoutLocationsAsync(params long[] ids)
		{
			return ScoutLocationsAsync(createAsHint: false, ids);
		}

		public long GetLocationIdFromName(string game, string locationName)
		{
			if (!cache.TryGetDataPackageFromCache(out var package))
			{
				return -1L;
			}
			if (gameLocationNameToIdMapping == null)
			{
				gameLocationNameToIdMapping = package.Games.ToDictionary((KeyValuePair<string, GameData> x) => x.Key, (KeyValuePair<string, GameData> x) => x.Value.LocationLookup.ToDictionary((KeyValuePair<string, long> y) => y.Key, (KeyValuePair<string, long> y) => y.Value));
			}
			if (!gameLocationNameToIdMapping.TryGetValue(game, out var value))
			{
				return -1L;
			}
			if (!value.TryGetValue(locationName, out var value2))
			{
				return -1L;
			}
			return value2;
		}

		public string GetLocationNameFromId(long locationId)
		{
			if (!cache.TryGetDataPackageFromCache(out var package))
			{
				return null;
			}
			if (locationIdToNameMapping == null)
			{
				locationIdToNameMapping = package.Games.Select((KeyValuePair<string, GameData> x) => x.Value).SelectMany((GameData x) => x.LocationLookup).ToDictionary((KeyValuePair<string, long> x) => x.Value, (KeyValuePair<string, long> x) => x.Key);
			}
			if (!locationIdToNameMapping.TryGetValue(locationId, out var value))
			{
				return null;
			}
			return value;
		}

		private void CheckLocations(ICollection<long> locationIds)
		{
			if (locationIds == null || !locationIds.Any())
			{
				return;
			}
			List<long> list = new List<long>();
			foreach (long locationId in locationIds)
			{
				allLocations.TryAdd(locationId);
				if (locationsChecked.TryAdd(locationId))
				{
					list.Add(locationId);
				}
			}
			missingLocations = allLocations.AsToReadOnlyCollectionExcept(locationsChecked);
			if (list.Any())
			{
				this.CheckedLocationsUpdated?.Invoke(new ReadOnlyCollection<long>(list));
			}
		}
	}
	public class MessageLogHelper
	{
		public delegate void MessageReceivedHandler(LogMessage message);

		private readonly IReceivedItemsHelper items;

		private readonly ILocationCheckHelper locations;

		private readonly IPlayerHelper players;

		private readonly IConnectionInfoProvider connectionInfo;

		public event MessageReceivedHandler OnMessageReceived;

		internal MessageLogHelper(IArchipelagoSocketHelper socket, IReceivedItemsHelper items, ILocationCheckHelper locations, IPlayerHelper players, IConnectionInfoProvider connectionInfo)
		{
			this.items = items;
			this.locations = locations;
			this.players = players;
			this.connectionInfo = connectionInfo;
			socket.PacketReceived += Socket_PacketReceived;
		}

		private void Socket_PacketReceived(ArchipelagoPacketBase packet)
		{
			if (this.OnMessageReceived != null && packet is PrintJsonPacket printJsonPacket)
			{
				TriggerOnMessageReceived(printJsonPacket);
			}
		}

		private void TriggerOnMessageReceived(PrintJsonPacket printJsonPacket)
		{
			foreach (PrintJsonPacket item in SplitPacketsPerLine(printJsonPacket))
			{
				MessagePart[] parsedData = GetParsedData(item);
				LogMessage message = ((item is ItemPrintJsonPacket itemPrintJsonPacket) ? new ItemSendLogMessage(parsedData, players, connectionInfo, itemPrintJsonPacket.ReceivingPlayer, itemPrintJsonPacket.Item.Player, itemPrintJsonPacket.Item) : ((item is ItemCheatPrintJsonPacket itemCheatPrintJsonPacket) ? new ItemCheatLogMessage(parsedData, players, connectionInfo, itemCheatPrintJsonPacket.Team, itemCheatPrintJsonPacket.ReceivingPlayer, itemCheatPrintJsonPacket.Item) : ((item is HintPrintJsonPacket hintPrintJsonPacket) ? new HintItemSendLogMessage(parsedData, players, connectionInfo, hintPrintJsonPacket.ReceivingPlayer, hintPrintJsonPacket.Item.Player, hintPrintJsonPacket.Item, hintPrintJsonPacket.Found.HasValue && hintPrintJsonPacket.Found.Value) : ((item is JoinPrintJsonPacket joinPrintJsonPacket) ? new JoinLogMessage(parsedData, players, connectionInfo, joinPrintJsonPacket.Team, joinPrintJsonPacket.Slot, joinPrintJsonPacket.Tags) : ((item is LeavePrintJsonPacket leavePrintJsonPacket) ? new LeaveLogMessage(parsedData, players, connectionInfo, leavePrintJsonPacket.Team, leavePrintJsonPacket.Slot) : ((item is ChatPrintJsonPacket chatPrintJsonPacket) ? new ChatLogMessage(parsedData, players, connectionInfo, chatPrintJsonPacket.Team, chatPrintJsonPacket.Slot, chatPrintJsonPacket.Message) : ((item is ServerChatPrintJsonPacket serverChatPrintJsonPacket) ? new ServerChatLogMessage(parsedData, serverChatPrintJsonPacket.Message) : ((item is TutorialPrintJsonPacket) ? new TutorialLogMessage(parsedData) : ((item is TagsChangedPrintJsonPacket tagsChangedPrintJsonPacket) ? new TagsChangedLogMessage(parsedData, players, connectionInfo, tagsChangedPrintJsonPacket.Team, tagsChangedPrintJsonPacket.Slot, tagsChangedPrintJsonPacket.Tags) : ((item is CommandResultPrintJsonPacket) ? new CommandResultLogMessage(parsedData) : ((item is AdminCommandResultPrintJsonPacket) ? new AdminCommandResultLogMessage(parsedData) : ((item is GoalPrintJsonPacket goalPrintJsonPacket) ? new GoalLogMessage(parsedData, players, connectionInfo, goalPrintJsonPacket.Team, goalPrintJsonPacket.Slot) : ((item is ReleasePrintJsonPacket releasePrintJsonPacket) ? new ReleaseLogMessage(parsedData, players, connectionInfo, releasePrintJsonPacket.Team, releasePrintJsonPacket.Slot) : ((item is CollectPrintJsonPacket collectPrintJsonPacket) ? new CollectLogMessage(parsedData, players, connectionInfo, collectPrintJsonPacket.Team, collectPrintJsonPacket.Slot) : ((!(item is CountdownPrintJsonPacket countdownPrintJsonPacket)) ? new LogMessage(parsedData) : new CountdownLogMessage(parsedData, countdownPrintJsonPacket.RemainingSeconds))))))))))))))));
				this.OnMessageReceived?.Invoke(message);
			}
		}

		private static IEnumerable<PrintJsonPacket> SplitPacketsPerLine(PrintJsonPacket printJsonPacket)
		{
			List<PrintJsonPacket> list = new List<PrintJsonPacket>();
			List<JsonMessagePart> list2 = new List<JsonMessagePart>();
			JsonMessagePart[] data = printJsonPacket.Data;
			foreach (JsonMessagePart jsonMessagePart in data)
			{
				string[] array = jsonMessagePart.Text.Split(new char[1] { '\n' });
				for (int j = 0; j < array.Length; j++)
				{
					string text = array[j];
					list2.Add(new JsonMessagePart
					{
						Text = text,
						Type = jsonMessagePart.Type,
						Color = jsonMessagePart.Color,
						Flags = jsonMessagePart.Flags,
						Player = jsonMessagePart.Player
					});
					if (j < array.Length - 1)
					{
						PrintJsonPacket printJsonPacket2 = CloneWithoutData(printJsonPacket);
						printJsonPacket2.Data = list2.ToArray();
						list.Add(printJsonPacket2);
						list2 = new List<JsonMessagePart>();
					}
				}
			}
			PrintJsonPacket printJsonPacket3 = CloneWithoutData(printJsonPacket);
			printJsonPacket3.Data = list2.ToArray();
			list.Add(printJsonPacket3);
			return list;
		}

		private static PrintJsonPacket CloneWithoutData(PrintJsonPacket source)
		{
			if (!(source is ItemPrintJsonPacket itemPrintJsonPacket))
			{
				if (!(source is ItemCheatPrintJsonPacket itemCheatPrintJsonPacket))
				{
					if (!(source is HintPrintJsonPacket hintPrintJsonPacket))
					{
						if (!(source is JoinPrintJsonPacket joinPrintJsonPacket))
						{
							if (!(source is LeavePrintJsonPacket leavePrintJsonPacket))
							{
								if (!(source is ChatPrintJsonPacket chatPrintJsonPacket))
								{
									if (!(source is ServerChatPrintJsonPacket serverChatPrintJsonPacket))
									{
										if (!(source is TutorialPrintJsonPacket tutorialPrintJsonPacket))
										{
											if (!(source is TagsChangedPrintJsonPacket tagsChangedPrintJsonPacket))
											{
												if (!(source is CommandResultPrintJsonPacket commandResultPrintJsonPacket))
												{
													if (!(source is AdminCommandResultPrintJsonPacket adminCommandResultPrintJsonPacket))
													{
														if (!(source is GoalPrintJsonPacket goalPrintJsonPacket))
														{
															if (!(source is ReleasePrintJsonPacket releasePrintJsonPacket))
															{
																if (!(source is CollectPrintJsonPacket collectPrintJsonPacket))
																{
																	if (source is CountdownPrintJsonPacket countdownPrintJsonPacket)
																	{
																		return new CountdownPrintJsonPacket
																		{
																			RemainingSeconds = countdownPrintJsonPacket.RemainingSeconds
																		};
																	}
																	return new PrintJsonPacket
																	{
																		MessageType = source.MessageType
																	};
																}
																return new CollectPrintJsonPacket
																{
																	MessageType = collectPrintJsonPacket.MessageType,
																	Team = collectPrintJsonPacket.Team,
																	Slot = collectPrintJsonPacket.Slot
																};
															}
															return new ReleasePrintJsonPacket
															{
																MessageType = releasePrintJsonPacket.MessageType,
																Team = releasePrintJsonPacket.Team,
																Slot = releasePrintJsonPacket.Slot
															};
														}
														return new GoalPrintJsonPacket
														{
															MessageType = goalPrintJsonPacket.MessageType,
															Team = goalPrintJsonPacket.Team,
															Slot = goalPrintJsonPacket.Slot
														};
													}
													return new AdminCommandResultPrintJsonPacket
													{
														MessageType = adminCommandResultPrintJsonPacket.MessageType
													};
												}
												return new CommandResultPrintJsonPacket
												{
													MessageType = commandResultPrintJsonPacket.MessageType
												};
											}
											return new TagsChangedPrintJsonPacket
											{
												MessageType = tagsChangedPrintJsonPacket.MessageType,
												Team = tagsChangedPrintJsonPacket.Team,
												Slot = tagsChangedPrintJsonPacket.Slot,
												Tags = tagsChangedPrintJsonPacket.Tags
											};
										}
										return new TutorialPrintJsonPacket
										{
											MessageType = tutorialPrintJsonPacket.MessageType
										};
									}
									return new ServerChatPrintJsonPacket
									{
										MessageType = serverChatPrintJsonPacket.MessageType,
										Message = serverChatPrintJsonPacket.Message
									};
								}
								return new ChatPrintJsonPacket
								{
									MessageType = chatPrintJsonPacket.MessageType,
									Team = chatPrintJsonPacket.Team,
									Slot = chatPrintJsonPacket.Slot,
									Message = chatPrintJsonPacket.Message
								};
							}
							return new LeavePrintJsonPacket
							{
								MessageType = leavePrintJsonPacket.MessageType,
								Team = leavePrintJsonPacket.Team,
								Slot = leavePrintJsonPacket.Slot
							};
						}
						return new JoinPrintJsonPacket
						{
							MessageType = joinPrintJsonPacket.MessageType,
							Team = joinPrintJsonPacket.Team,
							Slot = joinPrintJsonPacket.Slot,
							Tags = joinPrintJsonPacket.Tags
						};
					}
					return new HintPrintJsonPacket
					{
						MessageType = hintPrintJsonPacket.MessageType,
						ReceivingPlayer = hintPrintJsonPacket.ReceivingPlayer,
						Item = hintPrintJsonPacket.Item,
						Found = hintPrintJsonPacket.Found
					};
				}
				return new ItemCheatPrintJsonPacket
				{
					MessageType = itemCheatPrintJsonPacket.MessageType,
					ReceivingPlayer = itemCheatPrintJsonPacket.ReceivingPlayer,
					Item = itemCheatPrintJsonPacket.Item,
					Team = itemCheatPrintJsonPacket.Team
				};
			}
			return new ItemPrintJsonPacket
			{
				MessageType = itemPrintJsonPacket.MessageType,
				ReceivingPlayer = itemPrintJsonPacket.ReceivingPlayer,
				Item = itemPrintJsonPacket.Item
			};
		}

		internal MessagePart[] GetParsedData(PrintJsonPacket packet)
		{
			return packet.Data.Select(GetMessagePart).ToArray();
		}

		private MessagePart GetMessagePart(JsonMessagePart part)
		{
			switch (part.Type)
			{
			case JsonMessagePartType.ItemId:
			case JsonMessagePartType.ItemName:
				return new ItemMessagePart(items, part);
			case JsonMessagePartType.PlayerId:
			case JsonMessagePartType.PlayerName:
				return new PlayerMessagePart(players, connectionInfo, part);
			case JsonMessagePartType.LocationId:
			case JsonMessagePartType.LocationName:
				return new LocationMessagePart(locations, part);
			case JsonMessagePartType.EntranceName:
				return new EntranceMessagePart(part);
			default:
				return new MessagePart(MessagePartType.Text, part);
			}
		}
	}
	public interface IPlayerHelper
	{
		ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> Players { get; }

		IEnumerable<PlayerInfo> AllPlayers { get; }

		string GetPlayerAlias(int slot);

		string GetPlayerName(int slot);

		string GetPlayerAliasAndName(int slot);
	}
	public class PlayerHelper : IPlayerHelper
	{
		private readonly IConnectionInfoProvider connectionInfo;

		private ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> players = new ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>>(new Dictionary<int, ReadOnlyCollection<PlayerInfo>>(0));

		public ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>> Players => players;

		public IEnumerable<PlayerInfo> AllPlayers => players.SelectMany((KeyValuePair<int, ReadOnlyCollection<PlayerInfo>> kvp) => kvp.Value);

		internal PlayerHelper(IArchipelagoSocketHelper socket, IConnectionInfoProvider connectionInfo)
		{
			this.connectionInfo = connectionInfo;
			socket.PacketReceived += PacketReceived;
		}

		public string GetPlayerAlias(int slot)
		{
			if (players == null)
			{
				return null;
			}
			return players[connectionInfo.Team].FirstOrDefault((PlayerInfo p) => p.Slot == slot)?.Alias;
		}

		public string GetPlayerName(int slot)
		{
			if (players == null)
			{
				return null;
			}
			return players[connectionInfo.Team].FirstOrDefault((PlayerInfo p) => p.Slot == slot)?.Name;
		}

		public string GetPlayerAliasAndName(int slot)
		{
			if (players == null)
			{
				return null;
			}
			PlayerInfo playerInfo = players[connectionInfo.Team].FirstOrDefault((PlayerInfo p) => p.Slot == slot);
			if (playerInfo == null)
			{
				return null;
			}
			return playerInfo.Alias + " (" + playerInfo.Name + ")";
		}

		private void PacketReceived(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket connectedPacket))
			{
				if (packet is RoomUpdatePacket roomUpdatePacket)
				{
					UpdatePlayerInfo(roomUpdatePacket.Players);
				}
			}
			else
			{
				CreatePlayerInfo(connectedPacket.Players, connectedPacket.SlotInfo);
			}
		}

		private void CreatePlayerInfo(NetworkPlayer[] networkPlayers, Dictionary<int, NetworkSlot> slotInfos)
		{
			NetworkSlot[] source = ((slotInfos == null) ? new NetworkSlot[0] : slotInfos.Values.Where((NetworkSlot s) => s.Type == SlotType.Group).ToArray());
			int num = 0;
			int num2 = 0;
			NetworkPlayer[] array = networkPlayers;
			for (int i = 0; i < array.Length; i++)
			{
				NetworkPlayer networkPlayer = array[i];
				if (networkPlayer.Team > num)
				{
					num = networkPlayer.Team;
				}
				if (networkPlayer.Slot > num2)
				{
					num2 = networkPlayer.Slot;
				}
			}
			Dictionary<int, PlayerInfo[]> dictionary = new Dictionary<int, PlayerInfo[]>(num);
			for (int j = 0; j <= num; j++)
			{
				dictionary[j] = new PlayerInfo[num2 + 1];
				dictionary[j][0] = new PlayerInfo
				{
					Team = j,
					Slot = 0,
					Name = "Server",
					Alias = "Server",
					Game = "Archipelago",
					Groups = new NetworkSlot[0]
				};
			}
			array = networkPlayers;
			for (int i = 0; i < array.Length; i++)
			{
				NetworkPlayer p = array[i];
				dictionary[p.Team][p.Slot] = new PlayerInfo
				{
					Team = p.Team,
					Slot = p.Slot,
					Name = p.Name,
					Alias = p.Alias,
					Game = slotInfos?[p.Slot].Game,
					Groups = source.Where((NetworkSlot g) => g.GroupMembers.Contains(p.Slot)).ToArray()
				};
			}
			Dictionary<int, ReadOnlyCollection<PlayerInfo>> dictionary2 = new Dictionary<int, ReadOnlyCollection<PlayerInfo>>(dictionary.Count);
			foreach (KeyValuePair<int, PlayerInfo[]> item in dictionary)
			{
				dictionary2[item.Key] = new ReadOnlyCollection<PlayerInfo>(item.Value);
			}
			players = new ReadOnlyDictionary<int, ReadOnlyCollection<PlayerInfo>>(dictionary2);
		}

		private void UpdatePlayerInfo(NetworkPlayer[] networkPlayers)
		{
			if (networkPlayers != null && networkPlayers.Length != 0)
			{
				for (int i = 0; i < networkPlayers.Length; i++)
				{
					NetworkPlayer networkPlayer = networkPlayers[i];

ArchipelagoULTRAKILL.dll

Decompiled 2 weeks 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 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.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 UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
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("2.0.7")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("2.0.7.0")]
namespace ArchipelagoULTRAKILL
{
	public static class AudioManager
	{
		private static readonly Dictionary<string, string> multiMusicBattle = new Dictionary<string, string>
		{
			["1"] = "Assets/Music/0-1.wav",
			["2"] = "Assets/Music/0-2.wav",
			["3"] = "Assets/Music/0-1.wav",
			["4"] = "Assets/Music/0-2.wav",
			["6B"] = "Assets/Music/1-1.wav",
			["7B"] = "Assets/Music/1-2 Noise Battle.wav",
			["8"] = "Assets/Music/1-3.wav",
			["10"] = "Assets/Music/2-1.wav",
			["11"] = "Assets/Music/2-2.wav",
			["12"] = "Assets/Music/2-3.wav",
			["14A"] = "Assets/Music/3-1 Guts.wav",
			["14B"] = "Assets/Music/3-1 Glory.wav",
			["16"] = "Assets/Music/4-1.wav",
			["17"] = "Assets/Music/4-2.wav",
			["18A"] = "Assets/Music/4-3 Phase 1.wav",
			["18B"] = "Assets/Music/4-3 Phase 2.wav",
			["18C"] = "Assets/Music/4-3 Phase 3.wav",
			["20"] = "Assets/Music/5-1.wav",
			["22A"] = "Assets/Music/5-3.wav",
			["22B"] = "Assets/Music/5-3 Aftermath.wav",
			["24A"] = "Assets/Music/6-1.wav",
			["26B"] = "Assets/Music/7-1.wav",
			["27A"] = "Assets/Music/7-2 Intro Battle.wav",
			["27B"] = "Assets/Music/7-2.wav",
			["28B"] = "Assets/Music/7-3.wav",
			["667A"] = "Assets/Music/P-2.wav"
		};

		private static readonly Dictionary<string, string> multiMusicClean = new Dictionary<string, string>
		{
			["1"] = "Assets/Music/0-1 Clean.wav",
			["2"] = "Assets/Music/0-2 Clean.wav",
			["3"] = "Assets/Music/0-1 Clean.wav",
			["4"] = "Assets/Music/0-2 Clean.wav",
			["6B"] = "Assets/Music/1-1 Clean.wav",
			["7B"] = "Assets/Music/1-2 Noise Clean.wav",
			["8"] = "Assets/Music/1-3 Clean.wav",
			["10"] = "Assets/Music/2-1 Clean.wav",
			["11"] = "Assets/Music/2-2 Clean.wav",
			["12"] = "Assets/Music/2-3 Clean.wav",
			["14A"] = "Assets/Music/3-1 Guts Clean.wav",
			["14B"] = "Assets/Music/3-1 Glory Clean.wav",
			["16"] = "Assets/Music/4-1 Clean.wav",
			["17"] = "Assets/Music/4-2 Clean.wav",
			["18A"] = "Assets/Music/4-3 Phase 1 Clean.wav",
			["18B"] = "Assets/Music/4-3 Phase 2 Clean.wav",
			["18C"] = "Assets/Music/4-3 Phase 3.wav",
			["20"] = "Assets/Music/5-1 Clean.wav",
			["22A"] = "Assets/Music/5-3 Clean.wav",
			["22B"] = "Assets/Music/5-3 Aftermath Clean.wav",
			["24A"] = "Assets/Music/6-1 Clean.wav",
			["26B"] = "Assets/Music/7-1 Clean.wav",
			["27A"] = "Assets/Music/7-2 Intro Clean.wav",
			["27B"] = "Assets/Music/7-2 Clean.wav",
			["28B"] = "Assets/Music/7-3 Clean.wav",
			["667A"] = "Assets/Music/P-2 Clean.wav"
		};

		private static readonly Dictionary<string, string> singleMusic = new Dictionary<string, string>
		{
			["5"] = "Assets/Music/Bosses/Cerberus A.mp3",
			["6A"] = "Assets/Music/Misc/A Thousand Greetings.wav",
			["7A"] = "Assets/Music/Misc/A Thousand Greetings.wav",
			["9A"] = "Assets/Music/Misc/Clair_de_lune_(Claude_Debussy)_Suite_bergamasque (CREATIVE COMMONS).ogg",
			["9B"] = "Assets/Music/Bosses/V2 1-4.wav",
			["13"] = "Assets/Music/Bosses/Minos Corpse B.wav",
			["15A"] = "Assets/Music/Bosses/Gabriel 3-2 Intro.wav",
			["15B"] = "Assets/Music/Bosses/Gabriel 3-2.wav",
			["18D"] = "Assets/Music/Misc/themeofcancer.wav",
			["19"] = "Assets/Music/Bosses/V2 4-4.wav",
			["24B"] = "Assets/Music/6-1 Hall of Sacreligious Remains.wav",
			["25A"] = "Assets/Music/Bosses/Gabriel 6-2 Intro B.wav",
			["25B"] = "Assets/Music/Bosses/Gabriel 6-2.wav",
			["26A"] = "Assets/Music/7-1 Intro.wav",
			["26C"] = "Assets/Music/Misc/themeofcancer.wav",
			["26D"] = "Assets/Music/Bosses/Minotaur A.wav",
			["26E"] = "Assets/Music/Bosses/Minotaur B.wav",
			["28A"] = "Assets/Music/7-3 Intro Clean.wav",
			["666A"] = "Assets/Music/Bosses/Flesh Prison.wav",
			["666B"] = "Assets/Music/Bosses/Minos Prime.wav",
			["667B"] = "Assets/Music/Bosses/Flesh panopticon.wav",
			["667C"] = "Assets/Music/Bosses/Sisyphus Prime.wav"
		};

		public static AudioClip LoadNewSingleTrack(AudioClip source, string id)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (Core.data.music.ContainsKey(id))
			{
				id = Core.data.music[id];
				if (singleMusic.ContainsKey(id))
				{
					try
					{
						return Addressables.LoadAssetAsync<AudioClip>((object)singleMusic[id]).WaitForCompletion();
					}
					catch
					{
						Core.Logger.LogError((object)("Failed to load music track. (ID: " + id + " | Address: " + singleMusic[id]));
						return source;
					}
				}
				Core.Logger.LogError((object)("Couldn't find address for key " + id + ". Returning original source."));
				return source;
			}
			Core.Logger.LogError((object)("Music dictionary does not contain key " + id + ". Returning original source."));
			return source;
		}

		public static AudioClip LoadNewCleanTrack(AudioClip source, string id)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (Core.data.music.ContainsKey(id))
			{
				id = Core.data.music[id];
				if (multiMusicClean.ContainsKey(id))
				{
					try
					{
						return Addressables.LoadAssetAsync<AudioClip>((object)multiMusicClean[id]).WaitForCompletion();
					}
					catch
					{
						Core.Logger.LogError((object)("Failed to load music track. (ID: " + id + " | Address: " + multiMusicClean[id]));
						return source;
					}
				}
				Core.Logger.LogError((object)("Couldn't find address for key " + id + ". Returning original source."));
				return source;
			}
			Core.Logger.LogError((object)("Music dictionary does not contain key " + id + ". Returning original source."));
			return source;
		}

		public static AudioClip LoadNewBattleTrack(AudioClip source, string id)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (Core.data.music.ContainsKey(id))
			{
				id = Core.data.music[id];
				if (multiMusicBattle.ContainsKey(id))
				{
					try
					{
						return Addressables.LoadAssetAsync<AudioClip>((object)multiMusicBattle[id]).WaitForCompletion();
					}
					catch
					{
						Core.Logger.LogError((object)("Failed to load music track. (ID: " + id + " | Address: " + multiMusicBattle[id]));
						return source;
					}
				}
				Core.Logger.LogError((object)("Couldn't find address for key " + id + ". Returning original source."));
				return source;
			}
			Core.Logger.LogError((object)("Music dictionary does not contain key " + id + ". Returning original source."));
			return source;
		}

		public static void LoadMusicManagerTracks(string id, bool single = false)
		{
			if (single)
			{
				MonoSingleton<MusicManager>.Instance.cleanTheme.clip = LoadNewSingleTrack(MonoSingleton<MusicManager>.Instance.cleanTheme.clip, id);
				MonoSingleton<MusicManager>.Instance.battleTheme.clip = LoadNewSingleTrack(MonoSingleton<MusicManager>.Instance.battleTheme.clip, id);
				MonoSingleton<MusicManager>.Instance.bossTheme.clip = LoadNewSingleTrack(MonoSingleton<MusicManager>.Instance.bossTheme.clip, id);
			}
			else
			{
				MonoSingleton<MusicManager>.Instance.cleanTheme.clip = LoadNewCleanTrack(MonoSingleton<MusicManager>.Instance.cleanTheme.clip, id);
				MonoSingleton<MusicManager>.Instance.battleTheme.clip = LoadNewBattleTrack(MonoSingleton<MusicManager>.Instance.battleTheme.clip, id);
				MonoSingleton<MusicManager>.Instance.bossTheme.clip = LoadNewBattleTrack(MonoSingleton<MusicManager>.Instance.bossTheme.clip, id);
			}
		}

		public static void ChangeMusic()
		{
			if (Core.CurrentLevelInfo.Music == MusicType.Normal)
			{
				LoadMusicManagerTracks(Core.CurrentLevelInfo.Id.ToString());
			}
			else
			{
				switch (SceneHelper.CurrentScene)
				{
				default:
					return;
				case "Level 0-5":
					foreach (AudioSource item in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if ((Object)(object)((Component)item).transform.parent != (Object)null && (((Object)((Component)item).transform.parent).name == "4 Contents" || ((Object)((Component)item).transform.parent).name == "4 Contents(Clone)") && ((Object)((Component)item).transform).name == "Music")
						{
							item.clip = LoadNewSingleTrack(item.clip, "5");
							((Component)((Component)item).transform.parent.Find("Enemies").Find("StatueEnemy (1)")).GetComponent<SoundChanger>().newSound = LoadNewSingleTrack(item.clip, "5");
						}
					}
					break;
				case "Level 1-1":
					LoadMusicManagerTracks("6A", single: true);
					foreach (MusicChanger item2 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item2).gameObject).name == "MusicChanger")
						{
							item2.clean = LoadNewCleanTrack(item2.clean, "6B");
							item2.battle = LoadNewBattleTrack(item2.battle, "6B");
						}
					}
					break;
				case "Level 1-2":
					LoadMusicManagerTracks("7A", single: true);
					foreach (MusicChanger item3 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item3).gameObject).name == "MusicActivator")
						{
							item3.clean = LoadNewCleanTrack(item3.clean, "7B");
							item3.battle = LoadNewBattleTrack(item3.battle, "7B");
						}
					}
					break;
				case "Level 1-4":
					foreach (AudioSource item4 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item4).gameObject).name == "Music - Clair de Lune")
						{
							item4.clip = LoadNewSingleTrack(item4.clip, "9A");
						}
						else if (((Object)((Component)item4).gameObject).name == "Music - Versus")
						{
							item4.clip = LoadNewSingleTrack(item4.clip, "9B");
						}
					}
					break;
				case "Level 2-1":
					foreach (MusicChanger item5 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item5).gameObject).name == "Cube (1)")
						{
							item5.clean = LoadNewCleanTrack(item5.clean, "10");
							item5.battle = LoadNewBattleTrack(item5.battle, "10");
						}
					}
					break;
				case "Level 2-4":
					foreach (AudioSource item6 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item6).gameObject).name == "BossMusic")
						{
							item6.clip = LoadNewSingleTrack(item6.clip, "13");
						}
					}
					break;
				case "Level 3-1":
					LoadMusicManagerTracks("14A");
					foreach (MusicChanger item7 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item7).gameObject).name == "MusicChanger")
						{
							item7.clean = LoadNewCleanTrack(item7.clean, "14B");
							item7.battle = LoadNewBattleTrack(item7.battle, "14B");
						}
					}
					break;
				case "Level 3-2":
					foreach (AudioSource item8 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item8).gameObject).name == "Music 2")
						{
							item8.clip = LoadNewSingleTrack(item8.clip, "15A");
						}
						else if (((Object)((Component)item8).gameObject).name == "Music 3")
						{
							item8.clip = LoadNewSingleTrack(item8.clip, "15B");
						}
					}
					break;
				case "Level 4-3":
					foreach (MusicChanger item9 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item9).gameObject).name == "OnLight")
						{
							item9.clean = LoadNewCleanTrack(item9.clean, "18A");
							item9.battle = LoadNewBattleTrack(item9.battle, "18A");
						}
						else if (((Object)((Component)item9).gameObject).name == "Music Changer")
						{
							item9.clean = LoadNewCleanTrack(item9.clean, "18B");
							item9.battle = LoadNewBattleTrack(item9.battle, "18B");
						}
						else if (((Object)((Component)item9).gameObject).name == "Music Changer (Normal)")
						{
							item9.clean = LoadNewCleanTrack(item9.clean, "18B");
							item9.battle = LoadNewBattleTrack(item9.battle, "18B");
						}
						else if (((Object)((Component)item9).gameObject).name == "Music")
						{
							item9.clean = LoadNewCleanTrack(item9.clean, "18C");
							item9.battle = LoadNewBattleTrack(item9.battle, "18C");
						}
						else if (((Object)((Component)item9).gameObject).name == "Trigger (Fight)")
						{
							item9.clean = LoadNewSingleTrack(item9.clean, "18D");
							item9.battle = LoadNewSingleTrack(item9.battle, "18D");
							item9.boss = LoadNewSingleTrack(item9.boss, "18D");
						}
					}
					break;
				case "Level 4-4":
					foreach (AudioSource item10 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item10).gameObject).name == "Versus 2")
						{
							item10.clip = LoadNewSingleTrack(item10.clip, "19");
						}
					}
					break;
				case "Level 5-3":
					LoadMusicManagerTracks("22A");
					foreach (MusicChanger item11 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item11).gameObject).name == "InstantVer")
						{
							item11.clean = LoadNewCleanTrack(item11.clean, "22B");
							item11.battle = LoadNewBattleTrack(item11.battle, "22B");
						}
						else if (((Object)((Component)item11).gameObject).name == "NormalVer")
						{
							item11.clean = LoadNewCleanTrack(item11.clean, "22B");
							item11.battle = LoadNewBattleTrack(item11.battle, "22B");
						}
					}
					break;
				case "Level 6-1":
					foreach (MusicChanger item12 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item12).gameObject).name == "MusicChanger")
						{
							item12.clean = LoadNewCleanTrack(item12.clean, "24A");
							item12.battle = LoadNewBattleTrack(item12.battle, "24A");
						}
					}
					foreach (AudioSource item13 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item13).gameObject).name == "ClimaxMusic")
						{
							item13.clip = LoadNewSingleTrack(item13.clip, "24B");
						}
					}
					break;
				case "Level 6-2":
					foreach (AudioSource item14 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item14).gameObject).name == "Organ")
						{
							item14.clip = LoadNewSingleTrack(item14.clip, "25A");
						}
						else if (((Object)((Component)item14).gameObject).name == "BossMusic")
						{
							item14.clip = LoadNewSingleTrack(item14.clip, "25B");
						}
					}
					break;
				case "Level 7-1":
					foreach (MusicChanger item15 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)item15).name == "LevelMusicStart")
						{
							item15.clean = LoadNewCleanTrack(item15.clean, "26B");
							item15.battle = LoadNewBattleTrack(item15.battle, "26B");
							item15.boss = LoadNewBattleTrack(item15.battle, "26B");
						}
					}
					foreach (AudioSource item16 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)item16).name == "IntroMusic")
						{
							item16.clip = LoadNewSingleTrack(item16.clip, "26A");
						}
						else if (((Object)item16).name == "BigJohnatronMusic")
						{
							item16.clip = LoadNewSingleTrack(item16.clip, "26C");
						}
						else if (((Object)item16).name == "MinotaurPhase1Music")
						{
							item16.clip = LoadNewSingleTrack(item16.clip, "26D");
						}
						else if (((Object)item16).name == "MinotaurPhase2Music")
						{
							item16.clip = LoadNewSingleTrack(item16.clip, "26E");
						}
					}
					break;
				case "Level 7-2":
					LoadMusicManagerTracks("27A");
					foreach (MusicChanger item17 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)item17).name == "MusicActivator")
						{
							item17.clean = LoadNewCleanTrack(item17.clean, "27B");
							item17.battle = LoadNewBattleTrack(item17.battle, "27B");
							item17.boss = LoadNewBattleTrack(item17.battle, "27B");
						}
					}
					break;
				case "Level 7-3":
					LoadMusicManagerTracks("28A", single: true);
					foreach (MusicChanger item18 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)item18).name == "SecondTrackStart")
						{
							item18.clean = LoadNewCleanTrack(item18.clean, "28B");
							item18.battle = LoadNewBattleTrack(item18.battle, "28B");
							item18.boss = LoadNewBattleTrack(item18.battle, "28B");
						}
					}
					break;
				case "Level P-1":
					foreach (AudioSource item19 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item19).gameObject).name == "Chaos")
						{
							item19.clip = LoadNewSingleTrack(item19.clip, "666A");
						}
						else if (((Object)((Component)item19).gameObject).name == "Music 3")
						{
							item19.clip = LoadNewSingleTrack(item19.clip, "666B");
						}
					}
					break;
				case "Level P-2":
					foreach (MusicChanger item20 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item20).gameObject).name == "DelayedMusicActivator")
						{
							item20.clean = LoadNewCleanTrack(item20.clean, "667A");
							item20.battle = LoadNewBattleTrack(item20.battle, "667A");
							item20.boss = LoadNewBattleTrack(item20.battle, "667A");
						}
					}
					foreach (AudioSource item21 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item21).gameObject).name == "FleshPrison")
						{
							item21.clip = LoadNewSingleTrack(item21.clip, "667B");
						}
						else if (((Object)((Component)item21).gameObject).name == "Sisyphus")
						{
							item21.clip = LoadNewSingleTrack(item21.clip, "667C");
						}
					}
					break;
				}
			}
			Core.Logger.LogInfo((object)"Music changed successfully.");
		}
	}
	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 != 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 ConfigManager
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static OnClick <>9__65_0;

			public static OnClick <>9__65_1;

			public static OnClick <>9__65_2;

			public static OnClick <>9__65_3;

			public static PostStringValueChangeEvent <>9__65_4;

			public static BoolValueChangeEventDelegate <>9__65_5;

			public static IntValueChangeEventDelegate <>9__65_6;

			public static IntValueChangeEventDelegate <>9__65_7;

			public static OnClick <>9__65_8;

			public static OnClick <>9__65_9;

			public static OnClick <>9__65_10;

			public static OnClick <>9__65_11;

			internal void <Initialize>b__65_0()
			{
				if (Multiworld.Authenticated)
				{
					connectionInfo.text = "Already connected to server.";
				}
				else if (SceneHelper.CurrentScene != "Main Menu")
				{
					connectionInfo.text = "Can only connect to an Archipelago server on the main menu.";
				}
				else if ((GameProgressSaver.GetTutorial() || GameProgressSaver.GetIntro()) && !Core.DataExists() && !hintMode.value)
				{
					connectionInfo.text = "No Archipelago data found. Start a new save file before connecting.";
				}
				else if (Core.DataExists() && hintMode.value)
				{
					connectionInfo.text = "Can't use hint mode on a save file that already has randomizer data.";
				}
				else if (!Multiworld.Authenticated)
				{
					Core.data.slot_name = playerName.value;
					Core.data.host_name = serverAddress.value;
					Core.data.password = serverPassword.value;
					if (Core.data.password == "")
					{
						Core.data.password = null;
					}
					if (hintMode.value)
					{
						Multiworld.ConnectBK();
					}
					else
					{
						Multiworld.Connect();
					}
				}
			}

			internal void <Initialize>b__65_1()
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				if (Multiworld.Authenticated)
				{
					Multiworld.Disconnect();
					connectionInfo.text = "Disconnected from server.";
					if (SceneHelper.CurrentScene == "Main Menu")
					{
						((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red;
					}
				}
			}

			internal void <Initialize>b__65_2()
			{
				if (Multiworld.Authenticated)
				{
					Core.data.deathLink = true;
					Multiworld.EnableDeathLink();
				}
			}

			internal void <Initialize>b__65_3()
			{
				if (Multiworld.Authenticated)
				{
					Core.data.deathLink = false;
					Multiworld.DisableDeathLink();
				}
			}

			internal void <Initialize>b__65_4(string value)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Expected O, but got Unknown
				if (Multiworld.Authenticated)
				{
					if (value != "")
					{
						Multiworld.Session.Socket.SendPacket((ArchipelagoPacketBase)new SayPacket
						{
							Text = value
						});
					}
					chat.value = "";
				}
			}

			internal void <Initialize>b__65_5(BoolValueChangeEvent e)
			{
				((Component)UIManager.log).gameObject.SetActive(e.value);
			}

			internal void <Initialize>b__65_6(IntValueChangeEvent e)
			{
				UIManager.lines = e.value;
				while (Multiworld.messages.Count > e.value)
				{
					Multiworld.messages.RemoveAt(0);
				}
			}

			internal void <Initialize>b__65_7(IntValueChangeEvent e)
			{
				((TMP_Text)UIManager.log).fontSize = e.value;
			}

			internal void <Initialize>b__65_8()
			{
				UIManager.SetLogText("");
				Multiworld.messages.Clear();
			}

			internal void <Initialize>b__65_9()
			{
				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);
			}

			internal void <Initialize>b__65_10()
			{
				MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", false);
				MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", false);
				MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", false);
				MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", false);
				MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", false);
				MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", false);
				MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", false);
			}

			internal void <Initialize>b__65_11()
			{
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Expected O, but got Unknown
				//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Invalid comparison between Unknown and I4
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0183: 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_020d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0242: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				if (!Multiworld.Authenticated)
				{
					return;
				}
				Object.Destroy((Object)(object)Traverse.Create((object)hintList).Field("panelObject").GetValue<GameObject>());
				Traverse.Create((object)hintsPanel).Field("fieldObjects").GetValue<List<List<Transform>>>()
					.RemoveAt(2);
				Traverse.Create((object)hintsPanel).Field("fields").GetValue<List<ConfigField>>()
					.RemoveAt(2);
				hintList = null;
				hintList = new ConfigDivision(hintsPanel, "hintList");
				Hint[] hints = Multiworld.Session.DataStorage.GetHints((int?)null, (int?)null);
				Hint[] array = hints;
				foreach (Hint val in array)
				{
					if (!hintAdvancementOnly.value || (int)val.ItemFlags == 1)
					{
						if (Array.IndexOf(hints, val) != 0)
						{
							new ConfigHeader((ConfigPanel)(object)hintList, "-----", 24);
						}
						((ConfigField)new StringField((ConfigPanel)(object)hintList, "ITEM", $"hint{Array.IndexOf(hints, val)}_item", Multiworld.Session.Items.GetItemName(val.ItemId), true, false)).interactable = false;
						((ConfigField)new StringField((ConfigPanel)(object)hintList, "RECEIVING PLAYER", $"hint{Array.IndexOf(hints, val)}_receiving_player", Multiworld.Session.Players.GetPlayerAlias(val.ReceivingPlayer), true, false)).interactable = false;
						((ConfigField)new StringField((ConfigPanel)(object)hintList, "LOCATION", $"hint{Array.IndexOf(hints, val)}_location", Multiworld.Session.Locations.GetLocationNameFromId(val.LocationId), true, false)).interactable = false;
						((ConfigField)new StringField((ConfigPanel)(object)hintList, "SENDING PLAYER", $"hint{Array.IndexOf(hints, val)}_sending_player", Multiworld.Session.Players.GetPlayerAlias(val.FindingPlayer), true, false)).interactable = false;
						((ConfigField)new BoolField((ConfigPanel)(object)hintList, "FOUND", $"hint{Array.IndexOf(hints, val)}_found", val.Found, false)).interactable = false;
					}
				}
			}
		}

		public static PluginConfigurator config;

		public static ConfigPanel playerPanel;

		public static BoolField isConnected;

		public static StringField playerName;

		public static StringField serverAddress;

		public static StringField serverPassword;

		public static BoolField hintMode;

		public static ButtonField connectButton;

		public static ButtonField disconnectButton;

		public static ConfigHeader connectionInfo;

		public static ButtonField deathLinkOnButton;

		public static ButtonField deathLinkOffButton;

		public static StringField chat;

		public static StringField goal;

		public static StringField goalProgress;

		public static StringField locationsChecked;

		public static EnumField<BossOptions> bossRewards;

		public static BoolField challengeRewards;

		public static BoolField pRankRewards;

		public static BoolField fishRewards;

		public static BoolField randomizeFire2;

		public static BoolField randomizeSkulls;

		public static BoolField musicRandomizer;

		public static BoolField cybergrindHints;

		public static BoolField deathLink;

		public static ConfigPanel logPanel;

		public static BoolField showLog;

		public static IntField logLines;

		public static IntField logFontSize;

		public static ButtonField logClear;

		public static ConfigPanel colorPanel;

		public static EnumField<ColorOptions> uiColorRandomizer;

		public static EnumField<ColorOptions> gunColorRandomizer;

		public static ButtonField enableCustomButton;

		public static ButtonField disableCustomButton;

		public static ColorField APPlayerSelf;

		public static ColorField APPlayerOther;

		public static ColorField APItemAdvancement;

		public static ColorField APItemNeverExclude;

		public static ColorField APItemFiller;

		public static ColorField APItemTrap;

		public static ColorField APLocation;

		public static ColorField layer0Color;

		public static ColorField layer1Color;

		public static ColorField layer2Color;

		public static ColorField layer3Color;

		public static ColorField layer4Color;

		public static ColorField layer5Color;

		public static ColorField layer6Color;

		public static ColorField layer7Color;

		public static ColorField primeColor;

		public static ColorField altColor;

		public static ColorField arm0Color;

		public static ColorField arm1Color;

		public static ColorField arm2Color;

		public static ColorField blueSkullColor;

		public static ColorField redSkullColor;

		public static ColorField pointsColor;

		public static ColorField dualwieldColor;

		public static ColorField doublejumpColor;

		public static ColorField trapColor;

		public static ConfigPanel hintsPanel;

		public static BoolField hintAdvancementOnly;

		public static ButtonField hintRefresh;

		public static ConfigDivision hintList;

		public static void Initialize()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Expected O, but got Unknown
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Expected O, but got Unknown
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Expected O, but got Unknown
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Expected O, but got Unknown
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Expected O, but got Unknown
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Expected O, but got Unknown
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Expected O, but got Unknown
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Expected O, but got Unknown
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Expected O, but got Unknown
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Expected O, but got Unknown
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0408: Expected O, but got Unknown
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_042b: Expected O, but got Unknown
			//IL_043c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0441: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Expected O, but got Unknown
			//IL_045f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Expected O, but got Unknown
			//IL_0482: Unknown result type (might be due to invalid IL or missing references)
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Expected O, but got Unknown
			//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b7: Expected O, but got Unknown
			//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_04da: Expected O, but got Unknown
			//IL_04eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fd: Expected O, but got Unknown
			//IL_050e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0518: Expected O, but got Unknown
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Expected O, but got Unknown
			//IL_0557: Unknown result type (might be due to invalid IL or missing references)
			//IL_0561: Expected O, but got Unknown
			//IL_0531: Unknown result type (might be due to invalid IL or missing references)
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			//IL_053c: Expected O, but got Unknown
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ab: Expected O, but got Unknown
			//IL_057a: Unknown result type (might be due to invalid IL or missing references)
			//IL_057f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0585: Expected O, but got Unknown
			//IL_05e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ee: Expected O, but got Unknown
			//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cf: Expected O, but got Unknown
			//IL_06c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06cd: Expected O, but got Unknown
			//IL_0607: Unknown result type (might be due to invalid IL or missing references)
			//IL_060c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0612: Expected O, but got Unknown
			//IL_0706: Unknown result type (might be due to invalid IL or missing references)
			//IL_0710: Expected O, but got Unknown
			//IL_06e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f1: Expected O, but got Unknown
			//IL_0746: Unknown result type (might be due to invalid IL or missing references)
			//IL_076a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0770: Unknown result type (might be due to invalid IL or missing references)
			//IL_077a: Expected O, but got Unknown
			//IL_0798: Unknown result type (might be due to invalid IL or missing references)
			//IL_079e: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a8: Expected O, but got Unknown
			//IL_07c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_07cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d6: Expected O, but got Unknown
			//IL_07f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0804: Expected O, but got Unknown
			//IL_0822: Unknown result type (might be due to invalid IL or missing references)
			//IL_0828: Unknown result type (might be due to invalid IL or missing references)
			//IL_0832: Expected O, but got Unknown
			//IL_0850: Unknown result type (might be due to invalid IL or missing references)
			//IL_0856: Unknown result type (might be due to invalid IL or missing references)
			//IL_0860: Expected O, but got Unknown
			//IL_087e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0884: Unknown result type (might be due to invalid IL or missing references)
			//IL_088e: Expected O, but got Unknown
			//IL_089a: Unknown result type (might be due to invalid IL or missing references)
			//IL_08be: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ce: Expected O, but got Unknown
			//IL_08ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_08fc: Expected O, but got Unknown
			//IL_091a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0920: Unknown result type (might be due to invalid IL or missing references)
			//IL_092a: Expected O, but got Unknown
			//IL_0948: Unknown result type (might be due to invalid IL or missing references)
			//IL_094e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0958: Expected O, but got Unknown
			//IL_0976: Unknown result type (might be due to invalid IL or missing references)
			//IL_097c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0986: Expected O, but got Unknown
			//IL_09a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_09aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b4: Expected O, but got Unknown
			//IL_09d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_09d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_09e2: Expected O, but got Unknown
			//IL_0a00: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a06: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a10: Expected O, but got Unknown
			//IL_0a2e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a34: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a3e: Expected O, but got Unknown
			//IL_0a5c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a62: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a6c: Expected O, but got Unknown
			//IL_0a8a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a90: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a9a: Expected O, but got Unknown
			//IL_0ab8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0abe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac8: Expected O, but got Unknown
			//IL_0ae6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0af6: Expected O, but got Unknown
			//IL_0b14: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b1a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b24: Expected O, but got Unknown
			//IL_0b42: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b48: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b52: Expected O, but got Unknown
			//IL_0b70: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b76: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b80: Expected O, but got Unknown
			//IL_0b9e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bae: Expected O, but got Unknown
			//IL_0bcc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bd2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bdc: Expected O, but got Unknown
			//IL_0bfa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c00: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c0a: Expected O, but got Unknown
			//IL_0c1b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c25: Expected O, but got Unknown
			//IL_0c34: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c3e: Expected O, but got Unknown
			//IL_0c48: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c52: Expected O, but got Unknown
			//IL_0729: Unknown result type (might be due to invalid IL or missing references)
			//IL_072e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0734: Expected O, but got Unknown
			//IL_0c6b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c70: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c76: Expected O, but got Unknown
			if (config != null)
			{
				return;
			}
			config = PluginConfigurator.Create("Archipelago", "trpg.archipelagoultrakill");
			string text = Path.Combine(Core.workingDir, "icon.png");
			if (File.Exists(text))
			{
				config.SetIconWithURL(text);
			}
			new ConfigHeader(config.rootPanel, "ARCHIPELAGO", 24);
			playerPanel = new ConfigPanel(config.rootPanel, "PLAYER SETTINGS", "playerPanel");
			logPanel = new ConfigPanel(config.rootPanel, "LOG SETTINGS", "logPanel");
			colorPanel = new ConfigPanel(config.rootPanel, "COLOR SETTINGS", "colorPanel");
			hintsPanel = new ConfigPanel(config.rootPanel, "HINTS", "hintsPanel");
			isConnected = new BoolField(playerPanel, "CONNECTED TO SERVER?", "isConnected", false, false);
			((ConfigField)isConnected).interactable = false;
			playerName = new StringField(playerPanel, "NAME", "playerName", "V1", false, true);
			serverAddress = new StringField(playerPanel, "ADDRESS", "serverAddress", "archipelago.gg", false, true);
			serverPassword = new StringField(playerPanel, "PASSWORD", "serverPassword", "", true, true);
			hintMode = new BoolField(playerPanel, "HINT MODE", "hintMode", false, false);
			new ConfigHeader(playerPanel, "Hint mode disables all randomization, and allows connecting to other games' slots to unlock hints while playing The Cyber Grind.", 12, (TextAnchor)0);
			connectionInfo = new ConfigHeader(playerPanel, "", 16, (TextAnchor)1);
			connectButton = new ButtonField(playerPanel, "CONNECT", "connectButton");
			ButtonField obj = connectButton;
			object obj2 = <>c.<>9__65_0;
			if (obj2 == null)
			{
				OnClick val = delegate
				{
					if (Multiworld.Authenticated)
					{
						connectionInfo.text = "Already connected to server.";
					}
					else if (SceneHelper.CurrentScene != "Main Menu")
					{
						connectionInfo.text = "Can only connect to an Archipelago server on the main menu.";
					}
					else if ((GameProgressSaver.GetTutorial() || GameProgressSaver.GetIntro()) && !Core.DataExists() && !hintMode.value)
					{
						connectionInfo.text = "No Archipelago data found. Start a new save file before connecting.";
					}
					else if (Core.DataExists() && hintMode.value)
					{
						connectionInfo.text = "Can't use hint mode on a save file that already has randomizer data.";
					}
					else if (!Multiworld.Authenticated)
					{
						Core.data.slot_name = playerName.value;
						Core.data.host_name = serverAddress.value;
						Core.data.password = serverPassword.value;
						if (Core.data.password == "")
						{
							Core.data.password = null;
						}
						if (hintMode.value)
						{
							Multiworld.ConnectBK();
						}
						else
						{
							Multiworld.Connect();
						}
					}
				};
				<>c.<>9__65_0 = val;
				obj2 = (object)val;
			}
			obj.onClick += (OnClick)obj2;
			disconnectButton = new ButtonField(playerPanel, "DISCONNECT", "disconnectButton");
			ButtonField obj3 = disconnectButton;
			object obj4 = <>c.<>9__65_1;
			if (obj4 == null)
			{
				OnClick val2 = delegate
				{
					//IL_003f: Unknown result type (might be due to invalid IL or missing references)
					if (Multiworld.Authenticated)
					{
						Multiworld.Disconnect();
						connectionInfo.text = "Disconnected from server.";
						if (SceneHelper.CurrentScene == "Main Menu")
						{
							((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red;
						}
					}
				};
				<>c.<>9__65_1 = val2;
				obj4 = (object)val2;
			}
			obj3.onClick += (OnClick)obj4;
			deathLinkOnButton = new ButtonField(playerPanel, "ENABLE DEATH LINK", "deathLinkOnButton");
			ButtonField obj5 = deathLinkOnButton;
			object obj6 = <>c.<>9__65_2;
			if (obj6 == null)
			{
				OnClick val3 = delegate
				{
					if (Multiworld.Authenticated)
					{
						Core.data.deathLink = true;
						Multiworld.EnableDeathLink();
					}
				};
				<>c.<>9__65_2 = val3;
				obj6 = (object)val3;
			}
			obj5.onClick += (OnClick)obj6;
			deathLinkOffButton = new ButtonField(playerPanel, "DISABLE DEATH LINK", "deathLinkOffButton");
			ButtonField obj7 = deathLinkOffButton;
			object obj8 = <>c.<>9__65_3;
			if (obj8 == null)
			{
				OnClick val4 = delegate
				{
					if (Multiworld.Authenticated)
					{
						Core.data.deathLink = false;
						Multiworld.DisableDeathLink();
					}
				};
				<>c.<>9__65_3 = val4;
				obj8 = (object)val4;
			}
			obj7.onClick += (OnClick)obj8;
			chat = new StringField(playerPanel, "CHAT", "chat", "", true, false)
			{
				interactable = false
			};
			StringField obj9 = chat;
			object obj10 = <>c.<>9__65_4;
			if (obj10 == null)
			{
				PostStringValueChangeEvent val5 = delegate(string value)
				{
					//IL_0024: Unknown result type (might be due to invalid IL or missing references)
					//IL_0029: Unknown result type (might be due to invalid IL or missing references)
					//IL_0036: Expected O, but got Unknown
					if (Multiworld.Authenticated)
					{
						if (value != "")
						{
							Multiworld.Session.Socket.SendPacket((ArchipelagoPacketBase)new SayPacket
							{
								Text = value
							});
						}
						chat.value = "";
					}
				};
				<>c.<>9__65_4 = val5;
				obj10 = (object)val5;
			}
			obj9.postValueChangeEvent += (PostStringValueChangeEvent)obj10;
			new ConfigHeader(playerPanel, "-----", 24);
			goal = new StringField(playerPanel, "GOAL", "goal", "?", false, false)
			{
				interactable = false
			};
			goalProgress = new StringField(playerPanel, "LEVELS COMPLETED", "goalProgress", "?", false, false)
			{
				interactable = false
			};
			locationsChecked = new StringField(playerPanel, "LOCATIONS CHECKED", "locationsChecked", "?", false, false)
			{
				interactable = false
			};
			EnumField<BossOptions> obj11 = new EnumField<BossOptions>(playerPanel, "BOSS REWARDS", "bossRewards", BossOptions.Disabled, false);
			((ConfigField)obj11).interactable = false;
			bossRewards = obj11;
			bossRewards.SetEnumDisplayName(BossOptions.Disabled, "DISABLED");
			bossRewards.SetEnumDisplayName(BossOptions.Standard, "STANDARD");
			bossRewards.SetEnumDisplayName(BossOptions.Extended, "EXTENDED");
			challengeRewards = new BoolField(playerPanel, "CHALLENGE REWARDS", "challengeRewards", false, false)
			{
				interactable = false
			};
			pRankRewards = new BoolField(playerPanel, "P RANK REWARDS", "pRankRewards", false, false)
			{
				interactable = false
			};
			fishRewards = new BoolField(playerPanel, "FISH REWARDS", "fishRewards", false, false)
			{
				interactable = false
			};
			randomizeFire2 = new BoolField(playerPanel, "RANDOMIZE SECONDARY FIRE", "randomizeFire2", false, false)
			{
				interactable = false
			};
			randomizeSkulls = new BoolField(playerPanel, "RANDOMIZE SKULLS", "randomizeSkulls", false, false)
			{
				interactable = false
			};
			musicRandomizer = new BoolField(playerPanel, "MUSIC RANDOMIZER", "musicRandomizer", false, false)
			{
				interactable = false
			};
			cybergrindHints = new BoolField(playerPanel, "UNLOCK HINTS IN CYBERGRIND", "cybergrindHints", false, false)
			{
				interactable = false
			};
			deathLink = new BoolField(playerPanel, "DEATH LINK", "deathLink", false, false)
			{
				interactable = false
			};
			showLog = new BoolField(logPanel, "SHOW LOG", "showLog", true, true);
			BoolField obj12 = showLog;
			object obj13 = <>c.<>9__65_5;
			if (obj13 == null)
			{
				BoolValueChangeEventDelegate val6 = delegate(BoolValueChangeEvent e)
				{
					((Component)UIManager.log).gameObject.SetActive(e.value);
				};
				<>c.<>9__65_5 = val6;
				obj13 = (object)val6;
			}
			obj12.onValueChange += (BoolValueChangeEventDelegate)obj13;
			logLines = new IntField(logPanel, "NUMBER OF MESSAGES", "logLines", 5, 1, 16, true, true);
			IntField obj14 = logLines;
			object obj15 = <>c.<>9__65_6;
			if (obj15 == null)
			{
				IntValueChangeEventDelegate val7 = delegate(IntValueChangeEvent e)
				{
					UIManager.lines = e.value;
					while (Multiworld.messages.Count > e.value)
					{
						Multiworld.messages.RemoveAt(0);
					}
				};
				<>c.<>9__65_6 = val7;
				obj15 = (object)val7;
			}
			obj14.onValueChange += (IntValueChangeEventDelegate)obj15;
			logFontSize = new IntField(logPanel, "FONT SIZE", "logFontSize", 16, 1, 32, true, true);
			IntField obj16 = logFontSize;
			object obj17 = <>c.<>9__65_7;
			if (obj17 == null)
			{
				IntValueChangeEventDelegate val8 = delegate(IntValueChangeEvent e)
				{
					((TMP_Text)UIManager.log).fontSize = e.value;
				};
				<>c.<>9__65_7 = val8;
				obj17 = (object)val8;
			}
			obj16.onValueChange += (IntValueChangeEventDelegate)obj17;
			logClear = new ButtonField(logPanel, "CLEAR LOG", "logClear");
			ButtonField obj18 = logClear;
			object obj19 = <>c.<>9__65_8;
			if (obj19 == null)
			{
				OnClick val9 = delegate
				{
					UIManager.SetLogText("");
					Multiworld.messages.Clear();
				};
				<>c.<>9__65_8 = val9;
				obj19 = (object)val9;
			}
			obj18.onClick += (OnClick)obj19;
			uiColorRandomizer = new EnumField<ColorOptions>(colorPanel, "UI COLOR RANDOMIZER", "uiColorRandomizer", ColorOptions.Off, true);
			uiColorRandomizer.SetEnumDisplayName(ColorOptions.Off, "DISABLED");
			uiColorRandomizer.SetEnumDisplayName(ColorOptions.Once, "ONCE");
			uiColorRandomizer.SetEnumDisplayName(ColorOptions.EveryLoad, "EVERY NEW LEVEL LOADED");
			gunColorRandomizer = new EnumField<ColorOptions>(colorPanel, "GUN COLOR RANDOMIZER", "gunColorRandomizer", ColorOptions.Off, true);
			gunColorRandomizer.SetEnumDisplayName(ColorOptions.Off, "DISABLED");
			gunColorRandomizer.SetEnumDisplayName(ColorOptions.Once, "ONCE");
			gunColorRandomizer.SetEnumDisplayName(ColorOptions.EveryLoad, "EVERY NEW LEVEL LOADED");
			enableCustomButton = new ButtonField(colorPanel, "ENABLE ALL CUSTOM WEAPON COLORS", "enableCustomButton");
			ButtonField obj20 = enableCustomButton;
			object obj21 = <>c.<>9__65_9;
			if (obj21 == null)
			{
				OnClick val10 = delegate
				{
					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);
				};
				<>c.<>9__65_9 = val10;
				obj21 = (object)val10;
			}
			obj20.onClick += (OnClick)obj21;
			disableCustomButton = new ButtonField(colorPanel, "DISABLE ALL CUSTOM WEAPON COLORS", "disableCustomButton");
			ButtonField obj22 = disableCustomButton;
			object obj23 = <>c.<>9__65_10;
			if (obj23 == null)
			{
				OnClick val11 = delegate
				{
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", false);
				};
				<>c.<>9__65_10 = val11;
				obj23 = (object)val11;
			}
			obj22.onClick += (OnClick)obj23;
			new ConfigHeader(colorPanel, "ARCHIPELAGO COLORS", 24);
			APPlayerSelf = new ColorField(colorPanel, "PLAYER (YOU)", "APPlayerSelf", new Color(0.93f, 0f, 0.93f), true);
			APPlayerOther = new ColorField(colorPanel, "PLAYER (OTHERS)", "APPlayerOther", new Color(0.98f, 0.98f, 0.82f), true);
			APItemFiller = new ColorField(colorPanel, "ITEM (FILLER)", "APItemFiller", new Color(0f, 0.93f, 0.93f), true);
			APItemNeverExclude = new ColorField(colorPanel, "ITEM (USEFUL)", "APItemNeverExclude", new Color(0.43f, 0.55f, 0.91f), true);
			APItemAdvancement = new ColorField(colorPanel, "ITEM (PROGRESSION)", "APItemAdvancement", new Color(0.69f, 0.6f, 0.94f), true);
			APItemTrap = new ColorField(colorPanel, "ITEM (TRAP)", "APItemTrap", new Color(0.98f, 0.5f, 0.45f), true);
			APLocation = new ColorField(colorPanel, "LOCATION", "APLocation", new Color(0f, 1f, 0.5f), true);
			new ConfigHeader(colorPanel, "POPUP COLORS", 24);
			layer0Color = new ColorField(colorPanel, "LAYER 0", "layer0Color", new Color(1f, 0.5f, 0.25f), true);
			layer1Color = new ColorField(colorPanel, "LAYER 1", "layer1Color", new Color(0.2667f, 1f, 0.2706f), true);
			layer2Color = new ColorField(colorPanel, "LAYER 2", "layer2Color", new Color(0.765f, 0.25f, 1f), true);
			layer3Color = new ColorField(colorPanel, "LAYER 3", "layer3Color", new Color(1f, 0.9479f, 0.8566f), true);
			layer4Color = new ColorField(colorPanel, "LAYER 4", "layer4Color", new Color(1f, 1f, 0.25f), true);
			layer5Color = new ColorField(colorPanel, "LAYER 5", "layer5Color", new Color(0.251f, 0.9059f, 1f), true);
			layer6Color = new ColorField(colorPanel, "LAYER 6", "layer6Color", new Color(1f, 0.2353f, 0.2353f), true);
			layer7Color = new ColorField(colorPanel, "LAYER 7", "layer7Color", new Color(0.8f, 0.8f, 0.8f), true);
			primeColor = new ColorField(colorPanel, "PRIME SANCTUMS", "primeColor", new Color(1f, 0.2353f, 0.2353f), true);
			altColor = new ColorField(colorPanel, "ALTERNATE WEAPON", "altColor", new Color(1f, 0.65f, 0f), true);
			arm0Color = new ColorField(colorPanel, "FEEDBACKER", "arm0Color", new Color(0.251f, 0.9059f, 1f), true);
			arm1Color = new ColorField(colorPanel, "KNUCKLEBLASTER", "arm1Color", new Color(1f, 0.2353f, 0.2353f), true);
			arm2Color = new ColorField(colorPanel, "WHIPLASH", "arm2Color", new Color(0.2667f, 1f, 0.2706f), true);
			blueSkullColor = new ColorField(colorPanel, "BLUE SKULL", "blueSkullColor", new Color(0.251f, 0.9059f, 1f), true);
			redSkullColor = new ColorField(colorPanel, "RED SKULL", "redSkullColor", new Color(1f, 0.2353f, 0.2353f), true);
			pointsColor = new ColorField(colorPanel, "POINTS", "pointsColor", new Color(1f, 0.65f, 0f), true);
			dualwieldColor = new ColorField(colorPanel, "DUAL WIELD", "dualwieldColor", new Color(1f, 1f, 0.25f), true);
			doublejumpColor = new ColorField(colorPanel, "AIR JUMP", "doublejumpColor", new Color(1f, 1f, 0.6f), true);
			trapColor = new ColorField(colorPanel, "TRAP", "trapColor", new Color(0.7f, 0.7f, 0.7f), true);
			hintAdvancementOnly = new BoolField(hintsPanel, "PROGRESSION ITEM HINTS ONLY", "hintAdvancementOnly", true, true);
			hintRefresh = new ButtonField(hintsPanel, "REFRESH LIST", "hintRefresh");
			hintList = new ConfigDivision(hintsPanel, "hintList");
			ButtonField obj24 = hintRefresh;
			object obj25 = <>c.<>9__65_11;
			if (obj25 == null)
			{
				OnClick val12 = delegate
				{
					//IL_007d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0087: Expected O, but got Unknown
					//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
					//IL_00cf: Invalid comparison between Unknown and I4
					//IL_013e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0183: 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_020d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0242: Unknown result type (might be due to invalid IL or missing references)
					//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
					if (Multiworld.Authenticated)
					{
						Object.Destroy((Object)(object)Traverse.Create((object)hintList).Field("panelObject").GetValue<GameObject>());
						Traverse.Create((object)hintsPanel).Field("fieldObjects").GetValue<List<List<Transform>>>()
							.RemoveAt(2);
						Traverse.Create((object)hintsPanel).Field("fields").GetValue<List<ConfigField>>()
							.RemoveAt(2);
						hintList = null;
						hintList = new ConfigDivision(hintsPanel, "hintList");
						Hint[] hints = Multiworld.Session.DataStorage.GetHints((int?)null, (int?)null);
						Hint[] array = hints;
						foreach (Hint val13 in array)
						{
							if (!hintAdvancementOnly.value || (int)val13.ItemFlags == 1)
							{
								if (Array.IndexOf(hints, val13) != 0)
								{
									new ConfigHeader((ConfigPanel)(object)hintList, "-----", 24);
								}
								((ConfigField)new StringField((ConfigPanel)(object)hintList, "ITEM", $"hint{Array.IndexOf(hints, val13)}_item", Multiworld.Session.Items.GetItemName(val13.ItemId), true, false)).interactable = false;
								((ConfigField)new StringField((ConfigPanel)(object)hintList, "RECEIVING PLAYER", $"hint{Array.IndexOf(hints, val13)}_receiving_player", Multiworld.Session.Players.GetPlayerAlias(val13.ReceivingPlayer), true, false)).interactable = false;
								((ConfigField)new StringField((ConfigPanel)(object)hintList, "LOCATION", $"hint{Array.IndexOf(hints, val13)}_location", Multiworld.Session.Locations.GetLocationNameFromId(val13.LocationId), true, false)).interactable = false;
								((ConfigField)new StringField((ConfigPanel)(object)hintList, "SENDING PLAYER", $"hint{Array.IndexOf(hints, val13)}_sending_player", Multiworld.Session.Players.GetPlayerAlias(val13.FindingPlayer), true, false)).interactable = false;
								((ConfigField)new BoolField((ConfigPanel)(object)hintList, "FOUND", $"hint{Array.IndexOf(hints, val13)}_found", val13.Found, false)).interactable = false;
							}
						}
					}
				};
				<>c.<>9__65_11 = val12;
				obj25 = (object)val12;
			}
			obj24.onClick += (OnClick)obj25;
		}

		public static void LoadConnectionInfo()
		{
			if (Core.data.slot_name != null)
			{
				playerName.value = Core.data.slot_name;
			}
			if (Core.data.host_name != null)
			{
				serverAddress.value = Core.data.host_name;
			}
			if (Core.data.password != null)
			{
				serverPassword.value = Core.data.password;
			}
		}

		public static void LoadStats()
		{
			goal.value = Core.data.goal;
			goalProgress.value = $"{Core.data.completedLevels.Count} / {Core.data.goalRequirement}";
			string arg = ((LocationManager.locations.Count == 0) ? "?" : LocationManager.locations.Count.ToString());
			locationsChecked.value = $"{[email protected]} / {arg}";
			bossRewards.value = Core.data.bossRewards;
			challengeRewards.value = Core.data.challengeRewards;
			pRankRewards.value = Core.data.pRankRewards;
			fishRewards.value = Core.data.fishRewards;
			randomizeFire2.value = Core.data.randomizeFire2;
			randomizeSkulls.value = Core.data.randomizeSkulls;
			musicRandomizer.value = Core.data.musicRandomizer;
			cybergrindHints.value = Core.data.cybergrindHints;
			deathLink.value = Core.data.deathLink;
		}

		public static void ResetStatsDefaults()
		{
			goal.value = "?";
			goalProgress.value = "?";
			locationsChecked.value = "?";
			bossRewards.value = BossOptions.Disabled;
			challengeRewards.value = false;
			pRankRewards.value = false;
			fishRewards.value = false;
			randomizeFire2.value = false;
			randomizeSkulls.value = false;
			musicRandomizer.value = false;
			cybergrindHints.value = false;
			deathLink.value = false;
		}
	}
	public static class LevelManager
	{
		public static Dictionary<string, GameObject> skulls = new Dictionary<string, GameObject>();

		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
			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)
				{
					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 = "S";
				}
				string currentScene = SceneHelper.CurrentScene;
				string text2 = currentScene;
				if (!(text2 == "Level 1-4"))
				{
					if (text2 == "Level 5-1")
					{
						if (j + 1 > Core.data.unlockedSkulls5_1)
						{
							keyValuePair.Value.SetActive(false);
						}
					}
					else if (((Object)keyValuePair.Value).name.Contains("Blue"))
					{
						if (!Core.data.unlockedSkulls.Contains(text + "_b"))
						{
							keyValuePair.Value.SetActive(false);
						}
					}
					else if (((Object)keyValuePair.Value).name.Contains("Red") && !Core.data.unlockedSkulls.Contains(text + "_r"))
					{
						keyValuePair.Value.SetActive(false);
					}
				}
				else if (j + 1 > Core.data.unlockedSkulls1_4)
				{
					keyValuePair.Value.SetActive(false);
				}
			}
		}

		public static void UpdateShopVariation(VariationInfo variation)
		{
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Invalid comparison between Unknown and I4
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03df: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Invalid comparison between Unknown and I4
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Invalid comparison between Unknown and I4
			//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0676: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a0: Unknown result type (might be due to invalid IL or missing references)
			if (variation.weaponName == "arm0" && !Core.data.hasArm)
			{
				variation.costText.text = "<color=red>UNAVAILABLE</color>";
				((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "UNAVAILABLE";
				((Component)variation.equipButton).gameObject.SetActive(false);
				Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is not unlocked"));
				return;
			}
			if (variation.weaponName == "arm0" && Core.data.hasArm)
			{
				variation.costText.text = "ALREADY OWNED";
				((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "ALREADY OWNED";
				((Component)variation.equipButton).gameObject.SetActive(true);
				Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is unlocked"));
				return;
			}
			if (variation.weaponName == "arm1" || variation.weaponName == "arm2" || variation.weaponName == "sho2" || variation.weaponName == "nai2" || variation.weaponName == "rock2")
			{
				Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Skipping"));
				return;
			}
			if (!variation.weaponName.Contains("0"))
			{
				string text = "[Purchase to unlock: ";
				if (LocationManager.locations.ContainsKey("shop_" + variation.weaponName))
				{
					if (LocationManager.locations["shop_" + variation.weaponName].item is UKItem uKItem)
					{
						text = text + "<color=#" + ColorUtility.ToHtmlStringRGB(LocationManager.GetUKMessageColor(uKItem.itemName)) + "FF>" + uKItem.itemName + "</color>";
						if (uKItem.playerName != Core.data.slot_name)
						{
							text = text + "for <color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerOther) + "FF>" + uKItem.playerName + "</color>";
						}
						text += "]\n\n";
					}
					else if (LocationManager.locations["shop_" + variation.weaponName].item is APItem aPItem)
					{
						text = "<color=#" + ColorUtility.ToHtmlStringRGB(LocationManager.GetAPMessageColor(aPItem.type)) + "FF>" + aPItem.itemName + "</color>";
						text = text + " for <color=#" + ColorUtility.ToHtmlStringRGB(Colors.PlayerOther) + "FF>" + aPItem.playerName + "</color>";
						text += "]\n\n";
						text = (((int)aPItem.type == 1) ? (text + "You don't know what this is, but it seems <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemAdvancement) + "FF>important.</color>") : (((int)aPItem.type == 2) ? (text + "You don't know what this is, but it seems like it could be <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemNeverExclude) + "FF>useful.</color>") : (((int)aPItem.type != 4) ? (text + "You don't know what this is, but it seems like you could probably <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemFiller) + "FF>skip this</color> if you wanted to.") : (text + "You don't know what this is, but it seems like they're probably <color=#" + ColorUtility.ToHtmlStringRGB(Colors.ItemTrap) + "FF>better off without it.</color>"))));
					}
				}
				else
				{
					text = "???";
				}
				((TMP_Text)((Component)variation.varPage.transform.Find("Description")).GetComponent<TextMeshProUGUI>()).text = text;
			}
			GameProgressMoneyAndGear generalProgress = GameProgressSaver.GetGeneralProgress();
			FieldInfo field = typeof(GameProgressMoneyAndGear).GetField(variation.weaponName, BindingFlags.Instance | BindingFlags.Public);
			bool flag = int.Parse(field.GetValue(generalProgress).ToString()) == 1;
			if (flag && !variation.weaponName.Contains("0") && !Core.data.purchasedItems.Contains(variation.weaponName))
			{
				bool flag2 = false;
				if (GameProgressSaver.GetMoney() >= Core.shopPrices[variation.weaponName])
				{
					flag2 = true;
				}
				string text2 = ((!flag2) ? ("<color=red>" + MoneyText.DivideMoney(Core.shopPrices[variation.weaponName]) + "P</color>") : (MoneyText.DivideMoney(Core.shopPrices[variation.weaponName]) + "<color=orange>P</color>"));
				variation.costText.text = text2;
				((Component)((Component)variation.equipButton).transform.GetChild(0)).GetComponent<Image>().sprite = variation.equipSprites[MonoSingleton<PrefsManager>.Instance.GetInt("weapon." + variation.weaponName, 1)];
				variation.orderButtons.SetActive(true);
				Traverse val = Traverse.Create((object)variation);
				val.Field<int>("equipStatus").Value = MonoSingleton<PrefsManager>.Instance.GetInt("weapon." + variation.weaponName, 1);
				val.Field<int>("money").Value = GameProgressSaver.GetMoney();
				variation.varPage.GetComponentInChildren<MoneyText>().UpdateMoney();
				((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = text2;
				if (flag2)
				{
					((Graphic)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).color = new Color(1f, 1f, 1f);
					((Graphic)((Component)variation.buyButton).gameObject.GetComponent<Image>()).color = new Color(1f, 1f, 1f);
				}
				else
				{
					((Graphic)((Component)variation.buyButton).gameObject.GetComponent<Image>()).color = new Color(1f, 0f, 0f);
				}
				Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is unlocked, is not purchased"));
			}
			else if (!flag && !variation.weaponName.Contains("0") && Core.data.purchasedItems.Contains(variation.weaponName))
			{
				variation.costText.text = "ALREADY OWNED";
				variation.buyButton.deactivated = true;
				((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "ALREADY OWNED";
				((Graphic)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).color = new Color(0.5882f, 0.5882f, 0.5882f);
				((Component)variation.equipButton).gameObject.SetActive(false);
				Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is unlocked, is purchased"));
			}
			else if (!flag && variation.weaponName.Contains("0"))
			{
				variation.costText.text = "<color=red>UNAVAILABLE</color>";
				((TMP_Text)((Component)((Component)variation.buyButton).gameObject.transform.GetChild(0)).GetComponent<TextMeshProUGUI>()).text = "UNAVAILABLE";
				((Component)variation.equipButton).gameObject.SetActive(false);
				Core.Logger.LogInfo((object)("Shop - Weapon: \"" + variation.weaponName + "\" - Is not unlocked"));
			}
		}

		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" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent.parent).gameObject.GetComponent<ReverseDoorCloser>()))
					{
						((Component)((Component)val).transform.parent.parent.parent).gameObject.AddComponent<ReverseDoorCloser>();
					}
				}
				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" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent.parent).gameObject.GetComponent<ReverseDoorCloser>()))
					{
						((Component)((Component)val).transform.parent.parent.parent).gameObject.AddComponent<ReverseDoorCloser>();
					}
				}
				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)") && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent).gameObject.GetComponent<ReverseDoorCloser>()))
					{
						((Component)((Component)val).transform.parent).gameObject.AddComponent<ReverseDoorCloser>();
					}
				}
				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" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent.parent).gameObject.GetComponent<ReverseDoorCloser>()))
					{
						((Component)((Component)val).transform.parent.parent.parent).gameObject.AddComponent<ReverseDoorCloser>();
					}
				}
				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") && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent).gameObject.GetComponent<ReverseDoorCloser>()))
					{
						((Component)((Component)val).transform.parent.parent).gameObject.AddComponent<ReverseDoorCloser>();
					}
				}
				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" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent).gameObject.GetComponent<ReverseDoorCloser>()))
					{
						((Component)((Component)val).transform.parent.parent).gameObject.AddComponent<ReverseDoorCloser>();
					}
				}
				else if (SceneHelper.CurrentScene == "Level 6-1" && (Object)(object)((Component)val).transform.parent.parent != (Object)null && ((Object)((Component)val).transform.parent.parent).name == "3 - Crossroads" && !Object.op_Implicit((Object)(object)((Component)((Component)val).transform.parent.parent).gameObject.GetComponent<ReverseDoorCloser>()))
				{
					((Component)((Component)val).transform.parent.parent).gameObject.AddComponent<ReverseDoorCloser>();
				}
			}
		}

		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 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 class Multiworld
	{
		public static int[] AP_VERSION = new int[3] { 0, 4, 4 };

		public static DeathLinkService DeathLinkService = null;

		public static bool DeathLinkKilling = false;

		public static bool Authenticated;

		public static bool HintMode = false;

		public static ArchipelagoSession Session;

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

		public static void TryGetGoal(ref string goal, Dictionary<string, object> slotData, string defaultValue)
		{
			try
			{
				switch (int.Parse(slotData["goal"].ToString()))
				{
				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;
				}
			}
			catch (Exception)
			{
				Core.Logger.LogError((object)("Couldn't parse goal. Something has gone very wrong. Using default value (" + defaultValue + ")"));
				goal = 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 BossOptions option, Dictionary<string, object> slotData, string key, BossOptions defaultValue)
		{
			try
			{
				option = (BossOptions)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 bool Connect()
		{
			//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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_0834: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_072b: 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);
			Session.Items.ItemReceived += new ItemReceivedHandler(ItemReceived);
			LoginResult val = Session.TryConnectAndLogin("ULTRAKILL", Core.data.slot_name, (ItemsHandlingFlags)5, new Version(AP_VERSION[0], AP_VERSION[1], AP_VERSION[2]), (string[])null, (string)null, (Core.data.password == "") ? null : Core.data.password, true);
			LoginSuccessful val2 = (LoginSuccessful)(object)((val is LoginSuccessful) ? val : null);
			if (val2 != null)
			{
				Authenticated = true;
				ConfigManager.isConnected.value = true;
				((ConfigField)ConfigManager.playerName).interactable = false;
				((ConfigField)ConfigManager.serverAddress).interactable = false;
				((ConfigField)ConfigManager.serverPassword).interactable = false;
				((ConfigField)ConfigManager.hintMode).interactable = false;
				((ConfigField)ConfigManager.chat).interactable = true;
				TryGetGoal(ref Core.data.goal, val2.SlotData, "6-2");
				TryGetSlotDataValue(ref Core.data.goalRequirement, val2.SlotData, "goal_requirement", 15);
				TryGetSlotDataValue(ref Core.data.bossRewards, val2.SlotData, "boss_rewards", BossOptions.Disabled);
				TryGetSlotDataValue(ref Core.data.challengeRewards, val2.SlotData, "challenge_rewards", defaultValue: false);
				TryGetSlotDataValue(ref Core.data.pRankRewards, val2.SlotData, "p_rank_rewards", defaultValue: false);
				TryGetSlotDataValue(ref Core.data.fishRewards, val2.SlotData, "fish_rewards", defaultValue: false);
				TryGetSlotDataValue(ref Core.data.randomizeFire2, val2.SlotData, "randomize_secondary_fire", defaultValue: false);
				TryGetSlotDataValue(ref Core.data.randomizeSkulls, val2.SlotData, "randomize_skulls", defaultValue: false);
				if (Core.data.randomizeSkulls && UIManager.skullIcons.Count == 0)
				{
					UIManager.CreateSkullIcons();
				}
				if (!Core.DataExists())
				{
					TryGetSlotDataValue(ref Core.data.hasArm, val2.SlotData, "start_with_arm", defaultValue: true);
					TryGetSlotDataValue(ref Core.data.dashes, val2.SlotData, "starting_stamina", 3);
					TryGetSlotDataValue(ref Core.data.walljumps, val2.SlotData, "starting_walljumps", 3);
					TryGetSlotDataValue(ref Core.data.canSlide, val2.SlotData, "start_with_slide", defaultValue: true);
					TryGetSlotDataValue(ref Core.data.canSlam, val2.SlotData, "start_with_slam", defaultValue: true);
					TryGetSlotDataValue(ref Core.data.multiplier, val2.SlotData, "point_multiplier", 1);
					TryGetSlotDataValue(ref Core.data.musicRandomizer, val2.SlotData, "music_randomizer", defaultValue: false);
					if (Core.data.musicRandomizer)
					{
						Core.data.music = JsonConvert.DeserializeObject<Dictionary<string, string>>(val2.SlotData["music"].ToString());
					}
					TryGetSlotDataValue(ref Core.data.cybergrindHints, val2.SlotData, "cybergrind_hints", defaultValue: true);
					try
					{
						ConfigManager.uiColorRandomizer.value = (ColorOptions)Enum.Parse(typeof(ColorOptions), val2.SlotData["ui_color_randomizer"].ToString());
					}
					catch (KeyNotFoundException)
					{
						ConfigManager.uiColorRandomizer.value = ColorOptions.Off;
					}
					try
					{
						ConfigManager.gunColorRandomizer.value = (ColorOptions)Enum.Parse(typeof(ColorOptions), val2.SlotData["gun_color_randomizer"].ToString());
					}
					catch (KeyNotFoundException)
					{
						ConfigManager.gunColorRandomizer.value = ColorOptions.Off;
					}
					MonoSingleton<PrefsManager>.Instance.SetInt("difficulty", 4);
					MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 1);
					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(30);
					GameProgressSaver.SetPrime(1, 1);
					GameProgressSaver.SetPrime(2, 1);
					Core.SaveData();
					if (ConfigManager.uiColorRandomizer.value != 0)
					{
						ColorRandomizer.RandomizeUIColors();
					}
					if (ConfigManager.gunColorRandomizer.value != 0)
					{
						ColorRandomizer.RandomizeGunColors();
					}
					Core.data.deathLink = bool.Parse(val2.SlotData["death_link"].ToString());
				}
				if (Core.data.deathLink)
				{
					EnableDeathLink();
				}
				MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 1);
				LocationManager.locations.Clear();
				RawLocationData[] array = ((JToken)(JArray)val2.SlotData["locations"]).ToObject<RawLocationData[]>();
				foreach (RawLocationData rawLocationData in array)
				{
					AItem item = ((!rawLocationData.ukitem) ? ((AItem)new APItem
					{
						itemName = rawLocationData.item_name,
						playerName = rawLocationData.player_name,
						type = (ItemFlags)int.Parse(rawLocationData.item_type)
					}) : ((AItem)new UKItem
					{
						itemName = rawLocationData.item_name,
						playerName = rawLocationData.player_name,
						type = (UKType)int.Parse(rawLocationData.item_type)
					}));
					LocationManager.locations.Add(rawLocationData.id, new Location
					{
						id = rawLocationData.id,
						ap_id = rawLocationData.ap_id,
						item = item,
						@checked = Core.data.@checked.Contains(rawLocationData.id)
					});
				}
				if (Core.DataExists() && Core.data.@checked.Count > 0)
				{
					foreach (string item2 in Core.data.@checked)
					{
						LocationManager.CheckLocation(item2);
						if (LocationManager.locations[item2].item is UKItem uKItem && LocationManager.ShouldGetItemAgain(uKItem.type))
						{
							LocationManager.GetUKItem(uKItem, null, silent: true, save: false);
						}
					}
					Core.SaveData();
				}
				ConfigManager.LoadStats();
				Core.Logger.LogInfo((object)("Successfully connected to server as player \"" + Core.data.slot_name + "\"."));
				ConfigManager.connectionInfo.text = "Successfully connected to server as player \"" + Core.data.slot_name + "\".";
				((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Green;
				string text = ((LocationManager.locations.Count == 0) ? "?" : LocationManager.locations.Count.ToString());
				((TMP_Text)UIManager.menuText).text = "Archipelago\n2.0.7\nSlot " + (GameProgressSaver.currentSlot + 1) + "\n" + Core.data.@checked.Count + "/" + text;
			}
			else
			{
				LoginFailure val3 = (LoginFailure)(object)((val is LoginFailure) ? val : null);
				if (val3 != null)
				{
					Authenticated = false;
					Core.Logger.LogError((object)string.Join("\n", val3.Errors));
					ConfigManager.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 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_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: 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, new Version(AP_VERSION[0], AP_VERSION[1], AP_VERSION[2]), new string[1] { "TextOnly" }, (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;
				ConfigManager.isConnected.value = true;
				((ConfigField)ConfigManager.playerName).interactable = false;
				((ConfigField)ConfigManager.serverAddress).interactable = false;
				((ConfigField)ConfigManager.serverPassword).interactable = false;
				((ConfigField)ConfigManager.hintMode).interactable = false;
				((ConfigField)ConfigManager.chat).interactable = true;
				Core.Logger.LogInfo((object)("Successfully connected to server in hint mode as player \"" + Core.data.slot_name + "\"."));
				ConfigManager.connectionInfo.text = "Successfully connected to server in hint mode as player \"" + Core.data.slot_name + "\".";
				((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Green;
				((TMP_Text)UIManager.menuText).text = "Archipelago\n2.0.7\nSlot " + (GameProgressSaver.currentSlot + 1) + "\n<color=yellow>Hint Mode</color>";
			}
			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));
					ConfigManager.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)
			ConfigManager.isConnected.value = false;
			((ConfigField)ConfigManager.playerName).interactable = true;
			((ConfigField)ConfigManager.serverAddress).interactable = true;
			((ConfigField)ConfigManager.serverPassword).interactable = true;
			((ConfigField)ConfigManager.hintMode).interactable = true;
			((ConfigField)ConfigManager.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();
			Session = null;
			DeathLinkService = null;
			Authenticated = false;
			HintMode = false;
		}

		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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected I4, but got Unknown
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: 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_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Expected I4, but got Unknown
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: 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>";
			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 text6 = Session.Players.GetPlayerAlias(result3) ?? $"Slot: {result3}";
						text = text + text3 + text6 + "</color>";
						text2 += text6;
					}
					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 text5 = Session.Items.GetItemName(result2) ?? $"Item: {result2}";
						text = text + text3 + text5 + "</color>";
						text2 += text5;
					}
					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 text4 = Session.Locations.GetLocationNameFromId(result) ?? $"Location: {result}";
						text = text + text3 + text4 + "</color>";
						text2 += text4;
					}
					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)
		{
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			bool flag = LocationManager.ShouldGetItemAgain(LocationManager.GetTypeFromName(helper.PeekItemName()));
			bool silent = helper.Index <= Core.data.index &&

websocket-sharp.dll

Decompiled 2 weeks 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);