Decompiled source of PikunikuArchipelago v0.3.1

Archipelago.MultiClient.Net.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security.Authentication;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Archipelago.MultiClient.Net.Colors;
using Archipelago.MultiClient.Net.ConcurrentCollection;
using Archipelago.MultiClient.Net.Converters;
using Archipelago.MultiClient.Net.DataPackage;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Exceptions;
using Archipelago.MultiClient.Net.Extensions;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.MessageLog.Messages;
using Archipelago.MultiClient.Net.MessageLog.Parts;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using WebSocketSharp;

[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: AssemblyCompany("Jarno Westhof, Hussein Farran, Zach Parks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")]
[assembly: AssemblyFileVersion("6.7.0.0")]
[assembly: AssemblyInformationalVersion("6.7.0+c807746b6f1774cf1afe12af819acb078b55a333")]
[assembly: AssemblyProduct("Archipelago.MultiClient.Net")]
[assembly: AssemblyTitle("Archipelago.MultiClient.Net")]
[assembly: AssemblyVersion("6.7.0.0")]
internal interface IConcurrentHashSet<T>
{
	bool TryAdd(T item);

	bool Contains(T item);

	void UnionWith(T[] otherSet);

	T[] ToArray();

	ReadOnlyCollection<T> AsToReadOnlyCollection();

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

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

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

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

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

		IReceivedItemsHelper Items { get; }

		ILocationCheckHelper Locations { get; }

		IPlayerHelper Players { get; }

		IDataStorageHelper DataStorage { get; }

		IConnectionInfoProvider ConnectionInfo { get; }

		IRoomStateHelper RoomState { get; }

		IMessageLogHelper MessageLog { get; }

		IHintsHelper Hints { get; }

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

		private ConnectionInfoHelper connectionInfo;

		private volatile bool awaitingRoomInfo;

		private volatile bool expectingLoginResult;

		private LoginResult loginResult;

		public IArchipelagoSocketHelper Socket { get; }

		public IReceivedItemsHelper Items { get; }

		public ILocationCheckHelper Locations { get; }

		public IPlayerHelper Players { get; }

		public IDataStorageHelper DataStorage { get; }

		public IConnectionInfoProvider ConnectionInfo => connectionInfo;

		public IRoomStateHelper RoomState { get; }

		public IMessageLogHelper MessageLog { get; }

		public IHintsHelper Hints { get; }

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

		private void Socket_PacketReceived(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket) && !(packet is ConnectionRefusedPacket))
			{
				if (packet is RoomInfoPacket)
				{
					awaitingRoomInfo = false;
				}
			}
			else if (expectingLoginResult)
			{
				expectingLoginResult = false;
				loginResult = LoginResult.FromPacket(packet);
			}
		}

		public LoginResult TryConnectAndLogin(string game, string name, ItemsHandlingFlags itemsHandlingFlags, Version version = null, string[] tags = null, string uuid = null, string password = null, bool requestSlotData = true)
		{
			connectionInfo.SetConnectionParameters(game, tags, itemsHandlingFlags, uuid);
			try
			{
				awaitingRoomInfo = true;
				expectingLoginResult = true;
				loginResult = null;
				Socket.Connect();
				DateTime utcNow = DateTime.UtcNow;
				while (awaitingRoomInfo)
				{
					if (DateTime.UtcNow - utcNow > TimeSpan.FromSeconds(4.0))
					{
						Socket.Disconnect();
						return new LoginFailure("Connection timed out.");
					}
					Thread.Sleep(25);
				}
				Socket.SendPacket(BuildConnectPacket(name, password, version, requestSlotData));
				utcNow = DateTime.UtcNow;
				while (expectingLoginResult)
				{
					if (DateTime.UtcNow - utcNow > TimeSpan.FromSeconds(4.0))
					{
						Socket.Disconnect();
						return new LoginFailure("Connection timed out.");
					}
					Thread.Sleep(25);
				}
				Thread.Sleep(50);
				return loginResult;
			}
			catch (ArchipelagoSocketClosedException)
			{
				return new LoginFailure("Socket closed unexpectedly.");
			}
		}

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

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

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

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

		void SetClientState(ArchipelagoClientState state);

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

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

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

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

		public int Team { get; }

		public int Slot { get; }

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

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

		public ConnectionRefusedError[] ErrorCodes { get; }

		public string[] Errors { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public byte R { get; set; }

		public byte G { get; set; }

		public byte B { get; set; }

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

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

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

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

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

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

	}
	public class DataStorageElement
	{
		internal DataStorageElementContext Context;

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

		internal DataStorageHelper.DataStorageUpdatedHandler Callbacks;

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

		private JToken cachedValue;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public 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 void GetAsync<T>(Action<T> callback)
		{
			GetAsync(delegate(JToken t)
			{
				callback(t.ToObject<T>());
			});
		}

		public void GetAsync(Action<JToken> callback)
		{
			Context.GetAsync(Context.Key, callback);
		}

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

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

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

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

		private static bool IsNullable<T>()
		{
			if (typeof(T).IsGenericType)
			{
				return (object)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 Action<string, Action<JToken>> GetAsync { get; set; }

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


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


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

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

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

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

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

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

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

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

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

		public long ItemId { get; }

		public long LocationId { get; }

		public PlayerInfo Player { get; }

		public ItemFlags Flags { get; }

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

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

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

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

		public string ItemGame { get; }

		public string LocationGame { get; }

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

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

		public bool IsReceiverRelatedToActivePlayer { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public NetworkVersion()
		{
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public static OperationSpecification 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
			};
		}
	}
	public class AdditionalArgument
	{
		internal string Key { get; set; }

		internal JToken Value { get; set; }

		private AdditionalArgument()
		{
		}

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

		public long LocationId { get; set; }

		public int PlayerSlot { get; set; }

		public ItemFlags Flags { get; set; }

		public string ItemGame { get; set; }

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

		public PlayerInfo Player { get; set; }

		public string ItemName { get; set; }

		public string LocationName { get; set; }

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

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

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

		public static SerializableItemInfo FromJson(string json, IArchipelagoSession session = null)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			ItemInfoStreamingContext additional = ((session != null) ? new ItemInfoStreamingContext
			{
				Items = session.Items,
				Locations = session.Locations,
				PlayerHelper = session.Players,
				ConnectionInfo = session.ConnectionInfo
			} : null);
			JsonSerializerSettings val = new JsonSerializerSettings
			{
				Context = new StreamingContext(StreamingContextStates.Other, additional)
			};
			return JsonConvert.DeserializeObject<SerializableItemInfo>(json, val);
		}

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

		public ILocationCheckHelper Locations { get; set; }

		public IPlayerHelper PlayerHelper { get; set; }

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

		public long ItemId { get; }

		public int Player { get; }

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

		public int Player { get; }

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

		public MessagePartType Type { get; internal set; }

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

		public PaletteColor? PaletteColor { get; protected set; }

		public bool IsBackgroundColor { get; internal set; }

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

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

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

		public int SlotId { get; }

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

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

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

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

		public PlayerInfo Receiver { get; }

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer;

		public bool IsSenderTheActivePlayer => Sender == ActivePlayer;

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

		public ItemInfo Item { get; }

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

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

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

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

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

		public PlayerInfo Player { get; }

		public bool IsActivePlayer => Player == ActivePlayer;

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

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

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

		internal TagsChangedLogMessage(MessagePart[] parts, IPlayerHelper players, int team, int slot, string[] tags)
			: base(parts, players, team, slot)
		{
			Tags = tags;
		}
	}
	public class TutorialLogMessage : LogMessage
	{
		internal TutorialLogMessage(MessagePart[] parts)
			: base(parts)
		{
		}
	}
}
namespace Archipelago.MultiClient.Net.Helpers
{
	public class ArchipelagoSocketHelper : IArchipelagoSocketHelper
	{
		private const SslProtocols Tls13 = SslProtocols.Tls13;

		private const SslProtocols Tls12 = SslProtocols.Tls12;

		private static readonly ArchipelagoPacketConverter Converter = new ArchipelagoPacketConverter();

		internal WebSocket webSocket;

		public Uri Uri { get; }

		public bool Connected
		{
			get
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Invalid comparison between Unknown and I4
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Invalid comparison between Unknown and I4
				if (webSocket != null)
				{
					if ((int)webSocket.ReadyState != 1)
					{
						return (int)webSocket.ReadyState == 2;
					}
					return true;
				}
				return false;
			}
		}

		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 hostUrl)
		{
			Uri = hostUrl;
		}

		private WebSocket CreateWebSocket(Uri uri)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			WebSocket val = new WebSocket(uri.ToString(), new string[0]);
			if (val.IsSecure)
			{
				val.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
			}
			val.OnMessage += OnMessageReceived;
			val.OnError += OnError;
			val.OnClose += OnClose;
			val.OnOpen += OnOpen;
			return val;
		}

		public void Connect()
		{
			ConnectToProvidedUri(Uri);
		}

		private void ConnectToProvidedUri(Uri uri)
		{
			if (uri.Scheme != "unspecified")
			{
				try
				{
					webSocket = CreateWebSocket(uri);
					webSocket.Connect();
					return;
				}
				catch (Exception e)
				{
					OnError(e);
					return;
				}
			}
			List<Exception> list = new List<Exception>();
			try
			{
				try
				{
					ConnectToProvidedUri(uri.AsWss());
				}
				catch (Exception item)
				{
					list.Add(item);
					throw;
				}
				if (webSocket.IsAlive)
				{
					return;
				}
				try
				{
					ConnectToProvidedUri(uri.AsWs());
				}
				catch (Exception item2)
				{
					list.Add(item2);
					throw;
				}
			}
			catch
			{
				try
				{
					ConnectToProvidedUri(uri.AsWs());
				}
				catch (Exception item3)
				{
					list.Add(item3);
					OnError(new Archipelago.MultiClient.Net.Exceptions.AggregateException(list));
				}
			}
		}

		public void Disconnect()
		{
			if (webSocket != null && webSocket.IsAlive)
			{
				webSocket.Close();
			}
		}

		public void DisconnectAsync()
		{
			if (webSocket != null && webSocket.IsAlive)
			{
				webSocket.CloseAsync();
			}
		}

		public void SendPacket(ArchipelagoPacketBase packet)
		{
			SendMultiplePackets(packet);
		}

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

		public void SendMultiplePackets(params ArchipelagoPacketBase[] packets)
		{
			if (webSocket != null && webSocket.IsAlive)
			{
				string text = JsonConvert.SerializeObject((object)packets);
				webSocket.Send(text);
				if (this.PacketsSent != null)
				{
					this.PacketsSent(packets);
				}
				return;
			}
			throw new ArchipelagoSocketClosedException();
		}

		public void SendPacketAsync(ArchipelagoPacketBase packet, Action<bool> onComplete = null)
		{
			SendMultiplePacketsAsync(new List<ArchipelagoPacketBase> { packet }, onComplete);
		}

		public void SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets, Action<bool> onComplete = null)
		{
			SendMultiplePacketsAsync(onComplete, packets.ToArray());
		}

		public void SendMultiplePacketsAsync(Action<bool> onComplete = null, params ArchipelagoPacketBase[] packets)
		{
			if (webSocket.IsAlive)
			{
				string text = JsonConvert.SerializeObject((object)packets);
				webSocket.SendAsync(text, onComplete);
				if (this.PacketsSent != null)
				{
					this.PacketsSent(packets);
				}
				return;
			}
			throw new ArchipelagoSocketClosedException();
		}

		private void OnOpen(object sender, EventArgs e)
		{
			if (this.SocketOpened != null)
			{
				this.SocketOpened();
			}
		}

		private void OnClose(object sender, CloseEventArgs e)
		{
			if ((!(Uri.Scheme == "unspecified") || sender != webSocket || !(webSocket.Url.Scheme == "wss")) && this.SocketClosed != null)
			{
				this.SocketClosed(e.Reason);
			}
		}

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

		private void OnError(object sender, ErrorEventArgs e)
		{
			if (this.ErrorReceived != null)
			{
				this.ErrorReceived(e.Exception, e.Message);
			}
		}

		private void OnError(Exception e)
		{
			if (this.ErrorReceived != null)
			{
				this.ErrorReceived(e, e.Message);
			}
		}
	}
	public interface IConnectionInfoProvider
	{
		string Game { get; }

		int Team { get; }

		int Slot { get; }

		string[] Tags { get; }

		ItemsHandlingFlags ItemsHandlingFlags { get; }

		string Uuid { get; }

		void UpdateConnectionOptions(string[] tags);

		void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags);

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

		public string Game { get; private set; }

		public int Team { get; private set; }

		public int Slot { get; private set; }

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

		public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; }

		public string Uuid { get; private set; }

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

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

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

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

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

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

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

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

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

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

		private readonly Dictionary<string, Action<JToken>> asyncRetrievalCallbacks = new Dictionary<string, Action<JToken>>();

		private readonly IArchipelagoSocketHelper socket;

		private readonly IConnectionInfoProvider connectionInfoProvider;

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

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

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

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

		private void GetAsync(string key, Action<JToken> callback)
		{
			if (!asyncRetrievalCallbacks.ContainsKey(key))
			{
				asyncRetrievalCallbacks[key] = callback;
			}
			else
			{
				Dictionary<string, Action<JToken>> dictionary = asyncRetrievalCallbacks;
				dictionary[key] = (Action<JToken>)Delegate.Combine(dictionary[key], callback);
			}
			socket.SendPacketAsync(new GetPacket
			{
				Keys = new string[1] { key }
			});
		}

		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)
		{
			JToken value = null;
			GetAsync(key, delegate(JToken v)
			{
				value = v;
			});
			int num = 0;
			while (value == null)
			{
				Thread.Sleep(10);
				if (++num > 200)
				{
					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(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 value;
		}

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

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

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

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

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

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

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

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

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

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

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

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

		public void GetHintsAsync(Action<Hint[]> onHintsRetrieved, int? slot = null, int? team = null)
		{
			GetHintsElement(slot, team).GetAsync(delegate(JToken t)
			{
				onHintsRetrieved((t != null) ? t.ToObject<Hint[]>() : null);
			});
		}

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

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

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

		public void GetSlotDataAsync(Action<Dictionary<string, object>> onSlotDataRetrieved, int? slot = null)
		{
			GetSlotDataElement(slot).GetAsync(delegate(JToken t)
			{
				onSlotDataRetrieved((t != null) ? t.ToObject<Dictionary<string, object>>() : null);
			});
		}

		public void GetSlotDataAsync<T>(Action<T> onSlotDataRetrieved, int? slot = null) where T : class
		{
			GetSlotDataElement(slot).GetAsync(delegate(JToken t)
			{
				onSlotDataRetrieved((t != null) ? t.ToObject<T>() : null);
			});
		}

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

		public void GetItemNameGroupsAsync(Action<Dictionary<string, string[]>> onItemNameGroupsRetrieved, string game = null)
		{
			GetItemNameGroupsElement(game).GetAsync(delegate(JToken t)
			{
				onItemNameGroupsRetrieved((t != null) ? t.ToObject<Dictionary<string, string[]>>() : null);
			});
		}

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

		public void GetLocationNameGroupsAsync(Action<Dictionary<string, string[]>> onLocationNameGroupsRetrieved, string game = null)
		{
			GetLocationNameGroupsElement(game).GetAsync(delegate(JToken t)
			{
				onLocationNameGroupsRetrieved((t != null) ? t.ToObject<Dictionary<string, string[]>>() : null);
			});
		}

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

		public void GetClientStatusAsync(Action<ArchipelagoClientState> onStatusRetrieved, int? slot = null, int? team = null)
		{
			GetClientStatusElement(slot, team).GetAsync(delegate(JToken t)
			{
				onStatusRetrieved(t.ToObject<ArchipelagoClientState?>().GetValueOrDefault());
			});
		}

		public void TrackClientStatus(Action<ArchipelagoClientState> onStatusUpdated, bool retrieveCurrentClientStatus = true, int? slot = null, int? team = null)
		{
			GetClientStatusElement(slot, team).OnValueChanged += delegate(JToken _, JToken newValue, Dictionary<string, JToken> x)
			{
				onStatusUpdated(newValue.ToObject<ArchipelagoClientState>());
			};
			if (retrieveCurrentClientStatus)
			{
				GetClientStatusAsync(onStatusUpdated, slot, team);
			}
		}

		public bool GetRaceMode()
		{
			return GetRaceModeElement().To<int?>().GetValueOrDefault() > 0;
		}

		public void GetRaceModeAsync(Action<bool> onRaceModeRetrieved)
		{
			GetRaceModeElement().GetAsync(delegate(JToken t)
			{
				onRaceModeRetrieved(t.ToObject<int?>().GetValueOrDefault() > 0);
			});
		}
	}
	public interface IDataStorageWrapper
	{
		Hint[] GetHints(int? slot = null, int? team = null);

		void GetHintsAsync(Action<Hint[]> onHintsRetrieved, int? slot = null, int? team = null);

		void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null);

		Dictionary<string, object> GetSlotData(int? slot = null);

		T GetSlotData<T>(int? slot = null) where T : class;

		void GetSlotDataAsync(Action<Dictionary<string, object>> onSlotDataRetrieved, int? slot = null);

		void GetSlotDataAsync<T>(Action<T> onSlotDataRetrieved, int? slot = null) where T : class;

		Dictionary<string, string[]> GetItemNameGroups(string game = null);

		void GetItemNameGroupsAsync(Action<Dictionary<string, string[]>> onItemNameGroupsRetrieved, string game = null);

		Dictionary<string, string[]> GetLocationNameGroups(string game = null);

		void GetLocationNameGroupsAsync(Action<Dictionary<string, string[]>> onLocationNameGroupsRetrieved, string game = null);

		ArchipelagoClientState GetClientStatus(int? slot = null, int? team = null);

		void GetClientStatusAsync(Action<ArchipelagoClientState> onStatusRetrieved, int? slot = null, int? team = null);

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

		bool GetRaceMode();

		void GetRaceModeAsync(Action<bool> onRaceModeRetrieved);
	}
	public interface IHintsHelper
	{
		void CreateHints(int player, HintStatus hintStatus = HintStatus.Unspecified, params long[] locationIds);

		void CreateHints(HintStatus hintStatus = HintStatus.Unspecified, params long[] locationIds);

		void UpdateHintStatus(int player, long locationId, HintStatus newHintStatus);

		Hint[] GetHints(int? slot = null, int? team = null);

		void GetHintsAsync(Action<Hint[]> onHintsRetrieved, int? slot = null, int? team = null);

		void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null);
	}
	public class HintsHelper : IHintsHelper
	{
		private readonly IArchipelagoSocketHelper socket;

		private readonly ILocationCheckHelper locationCheckHelper;

		private readonly IRoomStateHelper roomStateHelper;

		private readonly IPlayerHelper players;

		private readonly IDataStorageHelper dataStorageHelper;

		internal HintsHelper(IArchipelagoSocketHelper socket, IPlayerHelper players, ILocationCheckHelper locationCheckHelper, IRoomStateHelper roomStateHelper, IDataStorageHelper dataStorageHelper)
		{
			this.socket = socket;
			this.players = players;
			this.locationCheckHelper = locationCheckHelper;
			this.roomStateHelper = roomStateHelper;
			this.dataStorageHelper = dataStorageHelper;
		}

		public void CreateHints(int player, HintStatus hintStatus = HintStatus.Unspecified, params long[] locationIds)
		{
			if (roomStateHelper.Version < new Version(0, 6, 2))
			{
				locationCheckHelper.ScoutLocationsAsync(null, createAsHint: true, locationIds);
				return;
			}
			socket.SendPacket(new CreateHintsPacket
			{
				Locations = locationIds,
				Player = player,
				Status = hintStatus
			});
		}

		public void CreateHints(HintStatus hintStatus = HintStatus.Unspecified, params long[] ids)
		{
			int slot = players.ActivePlayer.Slot;
			CreateHints(slot, hintStatus, ids);
		}

		public void UpdateHintStatus(int player, long locationId, HintStatus newHintStatus)
		{
			socket.SendPacket(new UpdateHintPacket
			{
				Location = locationId,
				Player = player,
				Status = newHintStatus
			});
		}

		public Hint[] GetHints(int? slot = null, int? team = null)
		{
			return dataStorageHelper.GetHints(slot, team);
		}

		public void GetHintsAsync(Action<Hint[]> onHintsRetrieved, int? slot = null, int? team = null)
		{
			dataStorageHelper.GetHintsAsync(onHintsRetrieved, slot, team);
		}

		public void TrackHints(Action<Hint[]> onHintsUpdated, bool retrieveCurrentlyUnlockedHints = true, int? slot = null, int? team = null)
		{
			dataStorageHelper.TrackHints(onHintsUpdated, retrieveCurrentlyUnlockedHints, slot, team);
		}
	}
	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);

		void Connect();

		void Disconnect();

		void SendPacketAsync(ArchipelagoPacketBase packet, Action<bool> onComplete = null);

		void SendMultiplePacketsAsync(List<ArchipelagoPacketBase> packets, Action<bool> onComplete = null);

		void SendMultiplePacketsAsync(Action<bool> onComplete = null, params ArchipelagoPacketBase[] packets);
	}
	public interface ILocationCheckHelper
	{
		ReadOnlyCollection<long> AllLocations { get; }

		ReadOnlyCollection<long> AllLocationsChecked { get; }

		ReadOnlyCollection<long> AllMissingLocations { get; }

		event LocationCheckHelper.CheckedLocationsUpdatedHandler CheckedLocationsUpdated;

		void CompleteLocationChecks(params long[] ids);

		void CompleteLocationChecksAsync(Action<bool> onComplete, params long[] ids);

		void ScoutLocationsAsync(Action<Dictionary<long, ScoutedItemInfo>> callback = null, HintCreationPolicy hintCreationPolicy = HintCreationPolicy.None, params long[] ids);

		void ScoutLocationsAsync(Action<Dictionary<long, ScoutedItemInfo>> callback = null, bool createAsHint = false, params long[] ids);

		void ScoutLocationsAsync(Action<Dictionary<long, ScoutedItemInfo>> callback = null, params long[] ids);

		long GetLocationIdFromName(string game, string locationName);

		string GetLocationNameFromId(long locationId, string game = null);
	}
	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 IItemInfoResolver itemInfoResolver;

		private readonly IConnectionInfoProvider connectionInfoProvider;

		private readonly IPlayerHelper players;

		private bool awaitingLocationInfoPacket;

		private Action<LocationInfoPacket> locationInfoPacketCallback;

		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, IItemInfoResolver itemInfoResolver, IConnectionInfoProvider connectionInfoProvider, IPlayerHelper players)
		{
			this.socket = socket;
			this.itemInfoResolver = itemInfoResolver;
			this.connectionInfoProvider = connectionInfoProvider;
			this.players = players;
			socket.PacketReceived += Socket_PacketReceived;
		}

		private void Socket_PacketReceived(ArchipelagoPacketBase packet)
		{
			if (!(packet is ConnectedPacket connectedPacket))

Newtonsoft.Json.dll

Decompiled 11 hours ago
#define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AllowPartiallyTrustedCallers]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Schema")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Tests")]
[assembly: InternalsVisibleTo("Newtonsoft.Json.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100cbd8d53b9d7de30f1f1278f636ec462cf9c254991291e66ebb157a885638a517887633b898ccbcf0d5c5ff7be85a6abe9e765d0ac7cd33c68dac67e7e64530e8222101109f154ab14a941c490ac155cd1d4fcba0fabb49016b4ef28593b015cab5937da31172f03f67d09edda404b88a60023f062ae71d0b2e4438b74cc11dc9")]
[assembly: AssemblyTrademark("")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyCompany("Newtonsoft")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCopyright("Copyright © James Newton-King 2008")]
[assembly: AssemblyDescription("Json.NET is a popular high-performance JSON framework for .NET")]
[assembly: AssemblyFileVersion("11.0.1")]
[assembly: AssemblyInformationalVersion("11.0.1-beta2+bdfeb80d3eb277241ce8f051a360c9461b33afc5")]
[assembly: AssemblyProduct("Json.NET")]
[assembly: AssemblyTitle("Json.NET .NET 3.5")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("11.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true)]
	internal sealed class NotNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
	internal sealed class NotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public NotNullWhenAttribute(bool returnValue)
		{
			ReturnValue = returnValue;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)]
	internal sealed class MaybeNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
	internal sealed class AllowNullAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	internal class DoesNotReturnIfAttribute : Attribute
	{
		public bool ParameterValue { get; }

		public DoesNotReturnIfAttribute(bool parameterValue)
		{
			ParameterValue = parameterValue;
		}
	}
}
namespace Newtonsoft.Json
{
	public enum ConstructorHandling
	{
		Default,
		AllowNonPublicDefaultConstructor
	}
	public enum DateFormatHandling
	{
		IsoDateFormat,
		MicrosoftDateFormat
	}
	public enum DateParseHandling
	{
		None,
		DateTime,
		DateTimeOffset
	}
	public enum DateTimeZoneHandling
	{
		Local,
		Utc,
		Unspecified,
		RoundtripKind
	}
	public class DefaultJsonNameTable : JsonNameTable
	{
		private class Entry
		{
			internal readonly string Value;

			internal readonly int HashCode;

			internal Entry Next;

			internal Entry(string value, int hashCode, Entry next)
			{
				Value = value;
				HashCode = hashCode;
				Next = next;
			}
		}

		private static readonly int HashCodeRandomizer;

		private int _count;

		private Entry[] _entries;

		private int _mask = 31;

		static DefaultJsonNameTable()
		{
			HashCodeRandomizer = Environment.TickCount;
		}

		public DefaultJsonNameTable()
		{
			_entries = new Entry[_mask + 1];
		}

		public override string? Get(char[] key, int start, int length)
		{
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			num += (num << 7) ^ key[start];
			int num2 = start + length;
			for (int i = start + 1; i < num2; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			int num3 = num & _mask;
			Entry[] entries = _entries;
			for (Entry entry = entries[num3]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && TextEquals(entry.Value, key, start, length))
				{
					return entry.Value;
				}
			}
			return null;
		}

		public string Add(string key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("key");
			}
			int length = key.Length;
			if (length == 0)
			{
				return string.Empty;
			}
			int num = length + HashCodeRandomizer;
			for (int i = 0; i < key.Length; i++)
			{
				num += (num << 7) ^ key[i];
			}
			num -= num >> 17;
			num -= num >> 11;
			num -= num >> 5;
			for (Entry entry = _entries[num & _mask]; entry != null; entry = entry.Next)
			{
				if (entry.HashCode == num && entry.Value.Equals(key, StringComparison.Ordinal))
				{
					return entry.Value;
				}
			}
			return AddEntry(key, num);
		}

		private string AddEntry(string str, int hashCode)
		{
			int num = hashCode & _mask;
			Entry entry = new Entry(str, hashCode, _entries[num]);
			_entries[num] = entry;
			if (_count++ == _mask)
			{
				Grow();
			}
			return entry.Value;
		}

		private void Grow()
		{
			Entry[] entries = _entries;
			int num = _mask * 2 + 1;
			Entry[] array = new Entry[num + 1];
			for (int i = 0; i < entries.Length; i++)
			{
				Entry entry = entries[i];
				while (entry != null)
				{
					int num2 = entry.HashCode & num;
					Entry next = entry.Next;
					entry.Next = array[num2];
					array[num2] = entry;
					entry = next;
				}
			}
			_entries = array;
			_mask = num;
		}

		private static bool TextEquals(string str1, char[] str2, int str2Start, int str2Length)
		{
			if (str1.Length != str2Length)
			{
				return false;
			}
			for (int i = 0; i < str1.Length; i++)
			{
				if (str1[i] != str2[str2Start + i])
				{
					return false;
				}
			}
			return true;
		}
	}
	[Flags]
	public enum DefaultValueHandling
	{
		Include = 0,
		Ignore = 1,
		Populate = 2,
		IgnoreAndPopulate = 3
	}
	public enum FloatFormatHandling
	{
		String,
		Symbol,
		DefaultValue
	}
	public enum FloatParseHandling
	{
		Double,
		Decimal
	}
	public enum Formatting
	{
		None,
		Indented
	}
	public interface IArrayPool<T>
	{
		T[] Rent(int minimumLength);

		void Return(T[]? array);
	}
	public interface IJsonLineInfo
	{
		int LineNumber { get; }

		int LinePosition { get; }

		bool HasLineInfo();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonArrayAttribute : JsonContainerAttribute
	{
		private bool _allowNullItems;

		public bool AllowNullItems
		{
			get
			{
				return _allowNullItems;
			}
			set
			{
				_allowNullItems = value;
			}
		}

		public JsonArrayAttribute()
		{
		}

		public JsonArrayAttribute(bool allowNullItems)
		{
			_allowNullItems = allowNullItems;
		}

		public JsonArrayAttribute(string id)
			: base(id)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false)]
	public sealed class JsonConstructorAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public abstract class JsonContainerAttribute : Attribute
	{
		internal bool? _isReference;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		private Type? _namingStrategyType;

		private object[]? _namingStrategyParameters;

		public string? Id { get; set; }

		public string? Title { get; set; }

		public string? Description { get; set; }

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType
		{
			get
			{
				return _namingStrategyType;
			}
			set
			{
				_namingStrategyType = value;
				NamingStrategyInstance = null;
			}
		}

		public object[]? NamingStrategyParameters
		{
			get
			{
				return _namingStrategyParameters;
			}
			set
			{
				_namingStrategyParameters = value;
				NamingStrategyInstance = null;
			}
		}

		internal NamingStrategy? NamingStrategyInstance { get; set; }

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		protected JsonContainerAttribute()
		{
		}

		protected JsonContainerAttribute(string id)
		{
			Id = id;
		}
	}
	public static class JsonConvert
	{
		public static readonly string True = "true";

		public static readonly string False = "false";

		public static readonly string Null = "null";

		public static readonly string Undefined = "undefined";

		public static readonly string PositiveInfinity = "Infinity";

		public static readonly string NegativeInfinity = "-Infinity";

		public static readonly string NaN = "NaN";

		public static Func<JsonSerializerSettings>? DefaultSettings { get; set; }

		public static string ToString(DateTime value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind);
		}

		public static string ToString(DateTime value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)
		{
			DateTime value2 = DateTimeUtils.EnsureDateTime(value, timeZoneHandling);
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeString(stringWriter, value2, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(DateTimeOffset value)
		{
			return ToString(value, DateFormatHandling.IsoDateFormat);
		}

		public static string ToString(DateTimeOffset value, DateFormatHandling format)
		{
			using StringWriter stringWriter = StringUtils.CreateStringWriter(64);
			stringWriter.Write('"');
			DateTimeUtils.WriteDateTimeOffsetString(stringWriter, value, format, null, CultureInfo.InvariantCulture);
			stringWriter.Write('"');
			return stringWriter.ToString();
		}

		public static string ToString(bool value)
		{
			return value ? True : False;
		}

		public static string ToString(char value)
		{
			return ToString(char.ToString(value));
		}

		public static string ToString(Enum value)
		{
			return value.ToString("D");
		}

		public static string ToString(int value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(short value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ushort value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(uint value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(long value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(ulong value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(float value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(float value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureFloatFormat(double value, string text, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			if (floatFormatHandling == FloatFormatHandling.Symbol || (!double.IsInfinity(value) && !double.IsNaN(value)))
			{
				return text;
			}
			if (floatFormatHandling == FloatFormatHandling.DefaultValue)
			{
				return (!nullable) ? "0.0" : Null;
			}
			return quoteChar + text + quoteChar;
		}

		public static string ToString(double value)
		{
			return EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture));
		}

		internal static string ToString(double value, FloatFormatHandling floatFormatHandling, char quoteChar, bool nullable)
		{
			return EnsureFloatFormat(value, EnsureDecimalPlace(value, value.ToString("R", CultureInfo.InvariantCulture)), floatFormatHandling, quoteChar, nullable);
		}

		private static string EnsureDecimalPlace(double value, string text)
		{
			if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1 || text.IndexOf('e') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		private static string EnsureDecimalPlace(string text)
		{
			if (text.IndexOf('.') != -1)
			{
				return text;
			}
			return text + ".0";
		}

		public static string ToString(byte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		[CLSCompliant(false)]
		public static string ToString(sbyte value)
		{
			return value.ToString(null, CultureInfo.InvariantCulture);
		}

		public static string ToString(decimal value)
		{
			return EnsureDecimalPlace(value.ToString(null, CultureInfo.InvariantCulture));
		}

		public static string ToString(Guid value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(Guid value, char quoteChar)
		{
			string text = value.ToString("D", CultureInfo.InvariantCulture);
			string text2 = quoteChar.ToString(CultureInfo.InvariantCulture);
			return text2 + text + text2;
		}

		public static string ToString(TimeSpan value)
		{
			return ToString(value, '"');
		}

		internal static string ToString(TimeSpan value, char quoteChar)
		{
			return ToString(value.ToString(), quoteChar);
		}

		public static string ToString(Uri? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ToString(value, '"');
		}

		internal static string ToString(Uri value, char quoteChar)
		{
			return ToString(value.OriginalString, quoteChar);
		}

		public static string ToString(string? value)
		{
			return ToString(value, '"');
		}

		public static string ToString(string? value, char delimiter)
		{
			return ToString(value, delimiter, StringEscapeHandling.Default);
		}

		public static string ToString(string? value, char delimiter, StringEscapeHandling stringEscapeHandling)
		{
			if (delimiter != '"' && delimiter != '\'')
			{
				throw new ArgumentException("Delimiter must be a single or double quote.", "delimiter");
			}
			return JavaScriptUtils.ToEscapedJavaScriptString(value, delimiter, appendDelimiters: true, stringEscapeHandling);
		}

		public static string ToString(object? value)
		{
			if (value == null)
			{
				return Null;
			}
			return ConvertUtils.GetTypeCode(value.GetType()) switch
			{
				PrimitiveTypeCode.String => ToString((string)value), 
				PrimitiveTypeCode.Char => ToString((char)value), 
				PrimitiveTypeCode.Boolean => ToString((bool)value), 
				PrimitiveTypeCode.SByte => ToString((sbyte)value), 
				PrimitiveTypeCode.Int16 => ToString((short)value), 
				PrimitiveTypeCode.UInt16 => ToString((ushort)value), 
				PrimitiveTypeCode.Int32 => ToString((int)value), 
				PrimitiveTypeCode.Byte => ToString((byte)value), 
				PrimitiveTypeCode.UInt32 => ToString((uint)value), 
				PrimitiveTypeCode.Int64 => ToString((long)value), 
				PrimitiveTypeCode.UInt64 => ToString((ulong)value), 
				PrimitiveTypeCode.Single => ToString((float)value), 
				PrimitiveTypeCode.Double => ToString((double)value), 
				PrimitiveTypeCode.DateTime => ToString((DateTime)value), 
				PrimitiveTypeCode.Decimal => ToString((decimal)value), 
				PrimitiveTypeCode.DateTimeOffset => ToString((DateTimeOffset)value), 
				PrimitiveTypeCode.Guid => ToString((Guid)value), 
				PrimitiveTypeCode.Uri => ToString((Uri)value), 
				PrimitiveTypeCode.TimeSpan => ToString((TimeSpan)value), 
				_ => throw new ArgumentException("Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.".FormatWith(CultureInfo.InvariantCulture, value.GetType())), 
			};
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value)
		{
			return SerializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting)
		{
			return SerializeObject(value, formatting, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Formatting formatting, JsonSerializerSettings? settings)
		{
			return SerializeObject(value, null, formatting, settings);
		}

		[DebuggerStepThrough]
		public static string SerializeObject(object? value, Type? type, Formatting formatting, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			jsonSerializer.Formatting = formatting;
			return SerializeObjectInternal(value, type, jsonSerializer);
		}

		private static string SerializeObjectInternal(object? value, Type? type, JsonSerializer jsonSerializer)
		{
			StringBuilder sb = new StringBuilder(256);
			StringWriter stringWriter = new StringWriter(sb, CultureInfo.InvariantCulture);
			using (JsonTextWriter jsonTextWriter = new JsonTextWriter(stringWriter))
			{
				jsonTextWriter.Formatting = jsonSerializer.Formatting;
				jsonSerializer.Serialize(jsonTextWriter, value, type);
			}
			return stringWriter.ToString();
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value)
		{
			return DeserializeObject(value, (Type?)null, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, JsonSerializerSettings settings)
		{
			return DeserializeObject(value, null, settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type)
		{
			return DeserializeObject(value, type, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value)
		{
			return JsonConvert.DeserializeObject<T>(value, (JsonSerializerSettings?)null);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject)
		{
			return DeserializeObject<T>(value);
		}

		[DebuggerStepThrough]
		public static T? DeserializeAnonymousType<T>(string value, T anonymousTypeObject, JsonSerializerSettings settings)
		{
			return DeserializeObject<T>(value, settings);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, params JsonConverter[] converters)
		{
			return (T)DeserializeObject(value, typeof(T), converters);
		}

		[DebuggerStepThrough]
		public static T? DeserializeObject<T>(string value, JsonSerializerSettings? settings)
		{
			return (T)DeserializeObject(value, typeof(T), settings);
		}

		[DebuggerStepThrough]
		public static object? DeserializeObject(string value, Type type, params JsonConverter[] converters)
		{
			JsonSerializerSettings settings = ((converters != null && converters.Length != 0) ? new JsonSerializerSettings
			{
				Converters = converters
			} : null);
			return DeserializeObject(value, type, settings);
		}

		public static object? DeserializeObject(string value, Type? type, JsonSerializerSettings? settings)
		{
			ValidationUtils.ArgumentNotNull(value, "value");
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			if (!jsonSerializer.IsCheckAdditionalContentSet())
			{
				jsonSerializer.CheckAdditionalContent = true;
			}
			using JsonTextReader reader = new JsonTextReader(new StringReader(value));
			return jsonSerializer.Deserialize(reader, type);
		}

		[DebuggerStepThrough]
		public static void PopulateObject(string value, object target)
		{
			PopulateObject(value, target, null);
		}

		public static void PopulateObject(string value, object target, JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
			using JsonReader jsonReader = new JsonTextReader(new StringReader(value));
			jsonSerializer.Populate(jsonReader, target);
			if (settings == null || !settings.CheckAdditionalContent)
			{
				return;
			}
			while (jsonReader.Read())
			{
				if (jsonReader.TokenType != JsonToken.Comment)
				{
					throw JsonSerializationException.Create(jsonReader, "Additional text found in JSON string after finishing deserializing object.");
				}
			}
		}
	}
	public abstract class JsonConverter
	{
		public virtual bool CanRead => true;

		public virtual bool CanWrite => true;

		public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);

		public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

		public abstract bool CanConvert(Type objectType);
	}
	public abstract class JsonConverter<T> : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (!((value != null) ? (value is T) : ReflectionUtils.IsNullable(typeof(T))))
			{
				throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			WriteJson(writer, (T)value, serializer);
		}

		public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			bool flag = existingValue == null;
			if (!flag && !(existingValue is T))
			{
				throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
			}
			return ReadJson(reader, objectType, flag ? default(T) : ((T)existingValue), !flag, serializer);
		}

		public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);

		public sealed override bool CanConvert(Type objectType)
		{
			return typeof(T).IsAssignableFrom(objectType);
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonConverterAttribute : Attribute
	{
		private readonly Type _converterType;

		public Type ConverterType => _converterType;

		public object[]? ConverterParameters { get; }

		public JsonConverterAttribute(Type converterType)
		{
			if ((object)converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			_converterType = converterType;
		}

		public JsonConverterAttribute(Type converterType, params object[] converterParameters)
			: this(converterType)
		{
			ConverterParameters = converterParameters;
		}
	}
	public class JsonConverterCollection : Collection<JsonConverter>
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonDictionaryAttribute : JsonContainerAttribute
	{
		public JsonDictionaryAttribute()
		{
		}

		public JsonDictionaryAttribute(string id)
			: base(id)
		{
		}
	}
	[Serializable]
	public class JsonException : Exception
	{
		public JsonException()
		{
		}

		public JsonException(string message)
			: base(message)
		{
		}

		public JsonException(string message, Exception? innerException)
			: base(message, innerException)
		{
		}

		public JsonException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		internal static JsonException Create(IJsonLineInfo lineInfo, string path, string message)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			return new JsonException(message);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public class JsonExtensionDataAttribute : Attribute
	{
		public bool WriteData { get; set; }

		public bool ReadData { get; set; }

		public JsonExtensionDataAttribute()
		{
			WriteData = true;
			ReadData = true;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonIgnoreAttribute : Attribute
	{
	}
	public abstract class JsonNameTable
	{
		public abstract string? Get(char[] key, int start, int length);
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false)]
	public sealed class JsonObjectAttribute : JsonContainerAttribute
	{
		private MemberSerialization _memberSerialization = MemberSerialization.OptOut;

		internal MissingMemberHandling? _missingMemberHandling;

		internal Required? _itemRequired;

		internal NullValueHandling? _itemNullValueHandling;

		public MemberSerialization MemberSerialization
		{
			get
			{
				return _memberSerialization;
			}
			set
			{
				_memberSerialization = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public NullValueHandling ItemNullValueHandling
		{
			get
			{
				return _itemNullValueHandling.GetValueOrDefault();
			}
			set
			{
				_itemNullValueHandling = value;
			}
		}

		public Required ItemRequired
		{
			get
			{
				return _itemRequired.GetValueOrDefault();
			}
			set
			{
				_itemRequired = value;
			}
		}

		public JsonObjectAttribute()
		{
		}

		public JsonObjectAttribute(MemberSerialization memberSerialization)
		{
			MemberSerialization = memberSerialization;
		}

		public JsonObjectAttribute(string id)
			: base(id)
		{
		}
	}
	internal enum JsonContainerType
	{
		None,
		Object,
		Array,
		Constructor
	}
	internal struct JsonPosition
	{
		private static readonly char[] SpecialCharacters = new char[18]
		{
			'.', ' ', '\'', '/', '"', '[', ']', '(', ')', '\t',
			'\n', '\r', '\f', '\b', '\\', '\u0085', '\u2028', '\u2029'
		};

		internal JsonContainerType Type;

		internal int Position;

		internal string? PropertyName;

		internal bool HasIndex;

		public JsonPosition(JsonContainerType type)
		{
			Type = type;
			HasIndex = TypeHasIndex(type);
			Position = -1;
			PropertyName = null;
		}

		internal int CalculateLength()
		{
			switch (Type)
			{
			case JsonContainerType.Object:
				return PropertyName.Length + 5;
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				return MathUtils.IntLength((ulong)Position) + 2;
			default:
				throw new ArgumentOutOfRangeException("Type");
			}
		}

		internal void WriteTo(StringBuilder sb, ref StringWriter? writer, ref char[]? buffer)
		{
			switch (Type)
			{
			case JsonContainerType.Object:
			{
				string propertyName = PropertyName;
				if (propertyName.IndexOfAny(SpecialCharacters) != -1)
				{
					sb.Append("['");
					if (writer == null)
					{
						writer = new StringWriter(sb);
					}
					JavaScriptUtils.WriteEscapedJavaScriptString(writer, propertyName, '\'', appendDelimiters: false, JavaScriptUtils.SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
					sb.Append("']");
				}
				else
				{
					if (sb.Length > 0)
					{
						sb.Append('.');
					}
					sb.Append(propertyName);
				}
				break;
			}
			case JsonContainerType.Array:
			case JsonContainerType.Constructor:
				sb.Append('[');
				sb.Append(Position);
				sb.Append(']');
				break;
			}
		}

		internal static bool TypeHasIndex(JsonContainerType type)
		{
			return type == JsonContainerType.Array || type == JsonContainerType.Constructor;
		}

		internal static string BuildPath(List<JsonPosition> positions, JsonPosition? currentPosition)
		{
			int num = 0;
			if (positions != null)
			{
				for (int i = 0; i < positions.Count; i++)
				{
					num += positions[i].CalculateLength();
				}
			}
			if (currentPosition.HasValue)
			{
				num += currentPosition.GetValueOrDefault().CalculateLength();
			}
			StringBuilder stringBuilder = new StringBuilder(num);
			StringWriter writer = null;
			char[] buffer = null;
			if (positions != null)
			{
				foreach (JsonPosition position in positions)
				{
					position.WriteTo(stringBuilder, ref writer, ref buffer);
				}
			}
			currentPosition?.WriteTo(stringBuilder, ref writer, ref buffer);
			return stringBuilder.ToString();
		}

		internal static string FormatMessage(IJsonLineInfo? lineInfo, string path, string message)
		{
			if (!message.EndsWith(Environment.NewLine, StringComparison.Ordinal))
			{
				message = message.Trim();
				if (!StringUtils.EndsWith(message, '.'))
				{
					message += ".";
				}
				message += " ";
			}
			message += "Path '{0}'".FormatWith(CultureInfo.InvariantCulture, path);
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				message += ", line {0}, position {1}".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition);
			}
			message += ".";
			return message;
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
	public sealed class JsonPropertyAttribute : Attribute
	{
		internal NullValueHandling? _nullValueHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal bool? _isReference;

		internal int? _order;

		internal Required? _required;

		internal bool? _itemIsReference;

		internal ReferenceLoopHandling? _itemReferenceLoopHandling;

		internal TypeNameHandling? _itemTypeNameHandling;

		public Type? ItemConverterType { get; set; }

		public object[]? ItemConverterParameters { get; set; }

		public Type? NamingStrategyType { get; set; }

		public object[]? NamingStrategyParameters { get; set; }

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameHandling = value;
			}
		}

		public bool IsReference
		{
			get
			{
				return _isReference.GetValueOrDefault();
			}
			set
			{
				_isReference = value;
			}
		}

		public int Order
		{
			get
			{
				return _order.GetValueOrDefault();
			}
			set
			{
				_order = value;
			}
		}

		public Required Required
		{
			get
			{
				return _required.GetValueOrDefault();
			}
			set
			{
				_required = value;
			}
		}

		public string? PropertyName { get; set; }

		public ReferenceLoopHandling ItemReferenceLoopHandling
		{
			get
			{
				return _itemReferenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_itemReferenceLoopHandling = value;
			}
		}

		public TypeNameHandling ItemTypeNameHandling
		{
			get
			{
				return _itemTypeNameHandling.GetValueOrDefault();
			}
			set
			{
				_itemTypeNameHandling = value;
			}
		}

		public bool ItemIsReference
		{
			get
			{
				return _itemIsReference.GetValueOrDefault();
			}
			set
			{
				_itemIsReference = value;
			}
		}

		public JsonPropertyAttribute()
		{
		}

		public JsonPropertyAttribute(string propertyName)
		{
			PropertyName = propertyName;
		}
	}
	public abstract class JsonReader : IDisposable
	{
		protected internal enum State
		{
			Start,
			Complete,
			Property,
			ObjectStart,
			Object,
			ArrayStart,
			Array,
			Closed,
			PostValue,
			ConstructorStart,
			Constructor,
			Error,
			Finished
		}

		private JsonToken _tokenType;

		private object? _value;

		internal char _quoteChar;

		internal State _currentState;

		private JsonPosition _currentPosition;

		private CultureInfo? _culture;

		private DateTimeZoneHandling _dateTimeZoneHandling;

		private int? _maxDepth;

		private bool _hasExceededMaxDepth;

		internal DateParseHandling _dateParseHandling;

		internal FloatParseHandling _floatParseHandling;

		private string? _dateFormatString;

		private List<JsonPosition>? _stack;

		protected State CurrentState => _currentState;

		public bool CloseInput { get; set; }

		public bool SupportMultipleContent { get; set; }

		public virtual char QuoteChar
		{
			get
			{
				return _quoteChar;
			}
			protected internal set
			{
				_quoteChar = value;
			}
		}

		public DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling;
			}
			set
			{
				if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateTimeZoneHandling = value;
			}
		}

		public DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling;
			}
			set
			{
				if (value < DateParseHandling.None || value > DateParseHandling.DateTimeOffset)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_dateParseHandling = value;
			}
		}

		public FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling;
			}
			set
			{
				if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_floatParseHandling = value;
			}
		}

		public string? DateFormatString
		{
			get
			{
				return _dateFormatString;
			}
			set
			{
				_dateFormatString = value;
			}
		}

		public int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
			}
		}

		public virtual JsonToken TokenType => _tokenType;

		public virtual object? Value => _value;

		public virtual Type? ValueType => _value?.GetType();

		public virtual int Depth
		{
			get
			{
				int num = _stack?.Count ?? 0;
				if (JsonTokenUtils.IsStartToken(TokenType) || _currentPosition.Type == JsonContainerType.None)
				{
					return num;
				}
				return num + 1;
			}
		}

		public virtual string Path
		{
			get
			{
				if (_currentPosition.Type == JsonContainerType.None)
				{
					return string.Empty;
				}
				JsonPosition? currentPosition = ((_currentState != State.ArrayStart && _currentState != State.ConstructorStart && _currentState != State.ObjectStart) ? new JsonPosition?(_currentPosition) : null);
				return JsonPosition.BuildPath(_stack, currentPosition);
			}
		}

		public CultureInfo Culture
		{
			get
			{
				return _culture ?? CultureInfo.InvariantCulture;
			}
			set
			{
				_culture = value;
			}
		}

		internal JsonPosition GetPosition(int depth)
		{
			if (_stack != null && depth < _stack.Count)
			{
				return _stack[depth];
			}
			return _currentPosition;
		}

		protected JsonReader()
		{
			_currentState = State.Start;
			_dateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
			_dateParseHandling = DateParseHandling.DateTime;
			_floatParseHandling = FloatParseHandling.Double;
			_maxDepth = 64;
			CloseInput = true;
		}

		private void Push(JsonContainerType value)
		{
			UpdateScopeWithFinishedValue();
			if (_currentPosition.Type == JsonContainerType.None)
			{
				_currentPosition = new JsonPosition(value);
				return;
			}
			if (_stack == null)
			{
				_stack = new List<JsonPosition>();
			}
			_stack.Add(_currentPosition);
			_currentPosition = new JsonPosition(value);
			if (!_maxDepth.HasValue || !(Depth + 1 > _maxDepth) || _hasExceededMaxDepth)
			{
				return;
			}
			_hasExceededMaxDepth = true;
			throw JsonReaderException.Create(this, "The reader's MaxDepth of {0} has been exceeded.".FormatWith(CultureInfo.InvariantCulture, _maxDepth));
		}

		private JsonContainerType Pop()
		{
			JsonPosition currentPosition;
			if (_stack != null && _stack.Count > 0)
			{
				currentPosition = _currentPosition;
				_currentPosition = _stack[_stack.Count - 1];
				_stack.RemoveAt(_stack.Count - 1);
			}
			else
			{
				currentPosition = _currentPosition;
				_currentPosition = default(JsonPosition);
			}
			if (_maxDepth.HasValue && Depth <= _maxDepth)
			{
				_hasExceededMaxDepth = false;
			}
			return currentPosition.Type;
		}

		private JsonContainerType Peek()
		{
			return _currentPosition.Type;
		}

		public abstract bool Read();

		public virtual int? ReadAsInt32()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is int value2)
				{
					return value2;
				}
				int num;
				try
				{
					num = Convert.ToInt32(value, CultureInfo.InvariantCulture);
				}
				catch (Exception ex)
				{
					throw JsonReaderException.Create(this, "Could not convert to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
				}
				SetToken(JsonToken.Integer, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadInt32String(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal int? ReadInt32String(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (int.TryParse(s, NumberStyles.Integer, Culture, out var result))
			{
				SetToken(JsonToken.Integer, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to integer: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual string? ReadAsString()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.String:
				return (string)Value;
			default:
				if (JsonTokenUtils.IsPrimitiveToken(contentToken))
				{
					object value = Value;
					if (value != null)
					{
						string text = ((!(value is IFormattable formattable)) ? ((value is Uri uri) ? uri.OriginalString : value.ToString()) : formattable.ToString(null, Culture));
						SetToken(JsonToken.String, text, updateIndex: false);
						return text;
					}
				}
				throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		public virtual byte[]? ReadAsBytes()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.StartObject:
			{
				ReadIntoWrappedTypeObject();
				byte[] array3 = ReadAsBytes();
				ReaderReadAndAssert();
				if (TokenType != JsonToken.EndObject)
				{
					throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
				}
				SetToken(JsonToken.Bytes, array3, updateIndex: false);
				return array3;
			}
			case JsonToken.String:
			{
				string text = (string)Value;
				Guid g;
				byte[] array2 = ((text.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((!ConvertUtils.TryConvertGuid(text, out g)) ? Convert.FromBase64String(text) : g.ToByteArray()));
				SetToken(JsonToken.Bytes, array2, updateIndex: false);
				return array2;
			}
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Bytes:
				if (Value is Guid guid)
				{
					byte[] array = guid.ToByteArray();
					SetToken(JsonToken.Bytes, array, updateIndex: false);
					return array;
				}
				return (byte[])Value;
			case JsonToken.StartArray:
				return ReadArrayIntoByteArray();
			default:
				throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal byte[] ReadArrayIntoByteArray()
		{
			List<byte> list = new List<byte>();
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
				}
			}
			while (!ReadArrayElementIntoByteArrayReportDone(list));
			byte[] array = list.ToArray();
			SetToken(JsonToken.Bytes, array, updateIndex: false);
			return array;
		}

		private bool ReadArrayElementIntoByteArrayReportDone(List<byte> buffer)
		{
			switch (TokenType)
			{
			case JsonToken.None:
				throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
			case JsonToken.Integer:
				buffer.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
				return false;
			case JsonToken.EndArray:
				return true;
			case JsonToken.Comment:
				return false;
			default:
				throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		public virtual double? ReadAsDouble()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is double value2)
				{
					return value2;
				}
				double num = Convert.ToDouble(value, CultureInfo.InvariantCulture);
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDoubleString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading double. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal double? ReadDoubleString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to double: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual bool? ReadAsBoolean()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				bool flag = Convert.ToBoolean(Value, CultureInfo.InvariantCulture);
				SetToken(JsonToken.Boolean, flag, updateIndex: false);
				return flag;
			}
			case JsonToken.String:
				return ReadBooleanString((string)Value);
			case JsonToken.Boolean:
				return (bool)Value;
			default:
				throw JsonReaderException.Create(this, "Error reading boolean. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal bool? ReadBooleanString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (bool.TryParse(s, out var result))
			{
				SetToken(JsonToken.Boolean, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to boolean: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual decimal? ReadAsDecimal()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Integer:
			case JsonToken.Float:
			{
				object value = Value;
				if (value is decimal value2)
				{
					return value2;
				}
				decimal num;
				try
				{
					num = Convert.ToDecimal(value, CultureInfo.InvariantCulture);
				}
				catch (Exception ex)
				{
					throw JsonReaderException.Create(this, "Could not convert to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, value), ex);
				}
				SetToken(JsonToken.Float, num, updateIndex: false);
				return num;
			}
			case JsonToken.String:
				return ReadDecimalString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal decimal? ReadDecimalString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (decimal.TryParse(s, NumberStyles.Number, Culture, out var result))
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			if (ConvertUtils.DecimalTryParse(s.ToCharArray(), 0, s.Length, out result) == ParseResult.Success)
			{
				SetToken(JsonToken.Float, result, updateIndex: false);
				return result;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to decimal: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTime? ReadAsDateTime()
		{
			switch (GetContentToken())
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTimeOffset dateTimeOffset)
				{
					SetToken(JsonToken.Date, dateTimeOffset.DateTime, updateIndex: false);
				}
				return (DateTime)Value;
			case JsonToken.String:
				return ReadDateTimeString((string)Value);
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
			}
		}

		internal DateTime? ReadDateTimeString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTime(s, DateTimeZoneHandling, _dateFormatString, Culture, out var dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTime.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				dt = DateTimeUtils.EnsureDateTime(dt, DateTimeZoneHandling);
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			throw JsonReaderException.Create(this, "Could not convert string to DateTime: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		public virtual DateTimeOffset? ReadAsDateTimeOffset()
		{
			JsonToken contentToken = GetContentToken();
			switch (contentToken)
			{
			case JsonToken.None:
			case JsonToken.Null:
			case JsonToken.EndArray:
				return null;
			case JsonToken.Date:
				if (Value is DateTime dateTime)
				{
					SetToken(JsonToken.Date, new DateTimeOffset(dateTime), updateIndex: false);
				}
				return (DateTimeOffset)Value;
			case JsonToken.String:
			{
				string s = (string)Value;
				return ReadDateTimeOffsetString(s);
			}
			default:
				throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, contentToken));
			}
		}

		internal DateTimeOffset? ReadDateTimeOffsetString(string? s)
		{
			if (StringUtils.IsNullOrEmpty(s))
			{
				SetToken(JsonToken.Null, null, updateIndex: false);
				return null;
			}
			if (DateTimeUtils.TryParseDateTimeOffset(s, _dateFormatString, Culture, out var dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
			{
				SetToken(JsonToken.Date, dt, updateIndex: false);
				return dt;
			}
			SetToken(JsonToken.String, s, updateIndex: false);
			throw JsonReaderException.Create(this, "Could not convert string to DateTimeOffset: {0}.".FormatWith(CultureInfo.InvariantCulture, s));
		}

		internal void ReaderReadAndAssert()
		{
			if (!Read())
			{
				throw CreateUnexpectedEndException();
			}
		}

		internal JsonReaderException CreateUnexpectedEndException()
		{
			return JsonReaderException.Create(this, "Unexpected end when reading JSON.");
		}

		internal void ReadIntoWrappedTypeObject()
		{
			ReaderReadAndAssert();
			if (Value != null && Value.ToString() == "$type")
			{
				ReaderReadAndAssert();
				if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal))
				{
					ReaderReadAndAssert();
					if (Value.ToString() == "$value")
					{
						return;
					}
				}
			}
			throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject));
		}

		public void Skip()
		{
			if (TokenType == JsonToken.PropertyName)
			{
				Read();
			}
			if (JsonTokenUtils.IsStartToken(TokenType))
			{
				int depth = Depth;
				while (Read() && depth < Depth)
				{
				}
			}
		}

		protected void SetToken(JsonToken newToken)
		{
			SetToken(newToken, null, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value)
		{
			SetToken(newToken, value, updateIndex: true);
		}

		protected void SetToken(JsonToken newToken, object? value, bool updateIndex)
		{
			_tokenType = newToken;
			_value = value;
			switch (newToken)
			{
			case JsonToken.StartObject:
				_currentState = State.ObjectStart;
				Push(JsonContainerType.Object);
				break;
			case JsonToken.StartArray:
				_currentState = State.ArrayStart;
				Push(JsonContainerType.Array);
				break;
			case JsonToken.StartConstructor:
				_currentState = State.ConstructorStart;
				Push(JsonContainerType.Constructor);
				break;
			case JsonToken.EndObject:
				ValidateEnd(JsonToken.EndObject);
				break;
			case JsonToken.EndArray:
				ValidateEnd(JsonToken.EndArray);
				break;
			case JsonToken.EndConstructor:
				ValidateEnd(JsonToken.EndConstructor);
				break;
			case JsonToken.PropertyName:
				_currentState = State.Property;
				_currentPosition.PropertyName = (string)value;
				break;
			case JsonToken.Raw:
			case JsonToken.Integer:
			case JsonToken.Float:
			case JsonToken.String:
			case JsonToken.Boolean:
			case JsonToken.Null:
			case JsonToken.Undefined:
			case JsonToken.Date:
			case JsonToken.Bytes:
				SetPostValueState(updateIndex);
				break;
			case JsonToken.Comment:
				break;
			}
		}

		internal void SetPostValueState(bool updateIndex)
		{
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
			if (updateIndex)
			{
				UpdateScopeWithFinishedValue();
			}
		}

		private void UpdateScopeWithFinishedValue()
		{
			if (_currentPosition.HasIndex)
			{
				_currentPosition.Position++;
			}
		}

		private void ValidateEnd(JsonToken endToken)
		{
			JsonContainerType jsonContainerType = Pop();
			if (GetTypeForCloseToken(endToken) != jsonContainerType)
			{
				throw JsonReaderException.Create(this, "JsonToken {0} is not valid for closing JsonType {1}.".FormatWith(CultureInfo.InvariantCulture, endToken, jsonContainerType));
			}
			if (Peek() != 0 || SupportMultipleContent)
			{
				_currentState = State.PostValue;
			}
			else
			{
				SetFinished();
			}
		}

		protected void SetStateBasedOnCurrent()
		{
			JsonContainerType jsonContainerType = Peek();
			switch (jsonContainerType)
			{
			case JsonContainerType.Object:
				_currentState = State.Object;
				break;
			case JsonContainerType.Array:
				_currentState = State.Array;
				break;
			case JsonContainerType.Constructor:
				_currentState = State.Constructor;
				break;
			case JsonContainerType.None:
				SetFinished();
				break;
			default:
				throw JsonReaderException.Create(this, "While setting the reader state back to current object an unexpected JsonType was encountered: {0}".FormatWith(CultureInfo.InvariantCulture, jsonContainerType));
			}
		}

		private void SetFinished()
		{
			_currentState = ((!SupportMultipleContent) ? State.Finished : State.Start);
		}

		private JsonContainerType GetTypeForCloseToken(JsonToken token)
		{
			return token switch
			{
				JsonToken.EndObject => JsonContainerType.Object, 
				JsonToken.EndArray => JsonContainerType.Array, 
				JsonToken.EndConstructor => JsonContainerType.Constructor, 
				_ => throw JsonReaderException.Create(this, "Not a valid close JsonToken: {0}".FormatWith(CultureInfo.InvariantCulture, token)), 
			};
		}

		void IDisposable.Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (_currentState != State.Closed && disposing)
			{
				Close();
			}
		}

		public virtual void Close()
		{
			_currentState = State.Closed;
			_tokenType = JsonToken.None;
			_value = null;
		}

		internal void ReadAndAssert()
		{
			if (!Read())
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal void ReadForTypeAndAssert(JsonContract? contract, bool hasConverter)
		{
			if (!ReadForType(contract, hasConverter))
			{
				throw JsonSerializationException.Create(this, "Unexpected end when reading JSON.");
			}
		}

		internal bool ReadForType(JsonContract? contract, bool hasConverter)
		{
			if (hasConverter)
			{
				return Read();
			}
			switch (contract?.InternalReadType ?? ReadType.Read)
			{
			case ReadType.Read:
				return ReadAndMoveToContent();
			case ReadType.ReadAsInt32:
				ReadAsInt32();
				break;
			case ReadType.ReadAsInt64:
			{
				bool result = ReadAndMoveToContent();
				if (TokenType == JsonToken.Undefined)
				{
					throw JsonReaderException.Create(this, "An undefined token is not a valid {0}.".FormatWith(CultureInfo.InvariantCulture, contract?.UnderlyingType ?? typeof(long)));
				}
				return result;
			}
			case ReadType.ReadAsDecimal:
				ReadAsDecimal();
				break;
			case ReadType.ReadAsDouble:
				ReadAsDouble();
				break;
			case ReadType.ReadAsBytes:
				ReadAsBytes();
				break;
			case ReadType.ReadAsBoolean:
				ReadAsBoolean();
				break;
			case ReadType.ReadAsString:
				ReadAsString();
				break;
			case ReadType.ReadAsDateTime:
				ReadAsDateTime();
				break;
			case ReadType.ReadAsDateTimeOffset:
				ReadAsDateTimeOffset();
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			return TokenType != JsonToken.None;
		}

		internal bool ReadAndMoveToContent()
		{
			return Read() && MoveToContent();
		}

		internal bool MoveToContent()
		{
			JsonToken tokenType = TokenType;
			while (tokenType == JsonToken.None || tokenType == JsonToken.Comment)
			{
				if (!Read())
				{
					return false;
				}
				tokenType = TokenType;
			}
			return true;
		}

		private JsonToken GetContentToken()
		{
			JsonToken tokenType;
			do
			{
				if (!Read())
				{
					SetToken(JsonToken.None);
					return JsonToken.None;
				}
				tokenType = TokenType;
			}
			while (tokenType == JsonToken.Comment);
			return tokenType;
		}
	}
	[Serializable]
	public class JsonReaderException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonReaderException()
		{
		}

		public JsonReaderException(string message)
			: base(message)
		{
		}

		public JsonReaderException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonReaderException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonReaderException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonReaderException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonReaderException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonReaderException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonReaderException(message, path, lineNumber, linePosition, ex);
		}
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public sealed class JsonRequiredAttribute : Attribute
	{
	}
	[Serializable]
	public class JsonSerializationException : JsonException
	{
		public int LineNumber { get; }

		public int LinePosition { get; }

		public string? Path { get; }

		public JsonSerializationException()
		{
		}

		public JsonSerializationException(string message)
			: base(message)
		{
		}

		public JsonSerializationException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		public JsonSerializationException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
		}

		public JsonSerializationException(string message, string path, int lineNumber, int linePosition, Exception? innerException)
			: base(message, innerException)
		{
			Path = path;
			LineNumber = lineNumber;
			LinePosition = linePosition;
		}

		internal static JsonSerializationException Create(JsonReader reader, string message)
		{
			return Create(reader, message, null);
		}

		internal static JsonSerializationException Create(JsonReader reader, string message, Exception? ex)
		{
			return Create(reader as IJsonLineInfo, reader.Path, message, ex);
		}

		internal static JsonSerializationException Create(IJsonLineInfo? lineInfo, string path, string message, Exception? ex)
		{
			message = JsonPosition.FormatMessage(lineInfo, path, message);
			int lineNumber;
			int linePosition;
			if (lineInfo != null && lineInfo.HasLineInfo())
			{
				lineNumber = lineInfo.LineNumber;
				linePosition = lineInfo.LinePosition;
			}
			else
			{
				lineNumber = 0;
				linePosition = 0;
			}
			return new JsonSerializationException(message, path, lineNumber, linePosition, ex);
		}
	}
	public class JsonSerializer
	{
		internal TypeNameHandling _typeNameHandling;

		internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling;

		internal PreserveReferencesHandling _preserveReferencesHandling;

		internal ReferenceLoopHandling _referenceLoopHandling;

		internal MissingMemberHandling _missingMemberHandling;

		internal ObjectCreationHandling _objectCreationHandling;

		internal NullValueHandling _nullValueHandling;

		internal DefaultValueHandling _defaultValueHandling;

		internal ConstructorHandling _constructorHandling;

		internal MetadataPropertyHandling _metadataPropertyHandling;

		internal JsonConverterCollection? _converters;

		internal IContractResolver _contractResolver;

		internal ITraceWriter? _traceWriter;

		internal IEqualityComparer? _equalityComparer;

		internal ISerializationBinder _serializationBinder;

		internal StreamingContext _context;

		private IReferenceResolver? _referenceResolver;

		private Formatting? _formatting;

		private DateFormatHandling? _dateFormatHandling;

		private DateTimeZoneHandling? _dateTimeZoneHandling;

		private DateParseHandling? _dateParseHandling;

		private FloatFormatHandling? _floatFormatHandling;

		private FloatParseHandling? _floatParseHandling;

		private StringEscapeHandling? _stringEscapeHandling;

		private CultureInfo _culture;

		private int? _maxDepth;

		private bool _maxDepthSet;

		private bool? _checkAdditionalContent;

		private string? _dateFormatString;

		private bool _dateFormatStringSet;

		public virtual IReferenceResolver? ReferenceResolver
		{
			get
			{
				return GetReferenceResolver();
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Reference resolver cannot be null.");
				}
				_referenceResolver = value;
			}
		}

		[Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
		public virtual SerializationBinder Binder
		{
			get
			{
				if (_serializationBinder is SerializationBinder result)
				{
					return result;
				}
				if (_serializationBinder is SerializationBinderAdapter serializationBinderAdapter)
				{
					return serializationBinderAdapter.SerializationBinder;
				}
				throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = (value as ISerializationBinder) ?? new SerializationBinderAdapter(value);
			}
		}

		public virtual ISerializationBinder SerializationBinder
		{
			get
			{
				return _serializationBinder;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value", "Serialization binder cannot be null.");
				}
				_serializationBinder = value;
			}
		}

		public virtual ITraceWriter? TraceWriter
		{
			get
			{
				return _traceWriter;
			}
			set
			{
				_traceWriter = value;
			}
		}

		public virtual IEqualityComparer? EqualityComparer
		{
			get
			{
				return _equalityComparer;
			}
			set
			{
				_equalityComparer = value;
			}
		}

		public virtual TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling;
			}
			set
			{
				if (value < TypeNameHandling.None || value > TypeNameHandling.Auto)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameHandling = value;
			}
		}

		[Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
		public virtual FormatterAssemblyStyle TypeNameAssemblyFormat
		{
			get
			{
				return (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
			}
		}

		public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
		{
			get
			{
				return _typeNameAssemblyFormatHandling;
			}
			set
			{
				if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_typeNameAssemblyFormatHandling = value;
			}
		}

		public virtual PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling;
			}
			set
			{
				if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_preserveReferencesHandling = value;
			}
		}

		public virtual ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling;
			}
			set
			{
				if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_referenceLoopHandling = value;
			}
		}

		public virtual MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling;
			}
			set
			{
				if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_missingMemberHandling = value;
			}
		}

		public virtual NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling;
			}
			set
			{
				if (value < NullValueHandling.Include || value > NullValueHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_nullValueHandling = value;
			}
		}

		public virtual DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling;
			}
			set
			{
				if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_defaultValueHandling = value;
			}
		}

		public virtual ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling;
			}
			set
			{
				if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_objectCreationHandling = value;
			}
		}

		public virtual ConstructorHandling ConstructorHandling
		{
			get
			{
				return _constructorHandling;
			}
			set
			{
				if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_constructorHandling = value;
			}
		}

		public virtual MetadataPropertyHandling MetadataPropertyHandling
		{
			get
			{
				return _metadataPropertyHandling;
			}
			set
			{
				if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_metadataPropertyHandling = value;
			}
		}

		public virtual JsonConverterCollection Converters
		{
			get
			{
				if (_converters == null)
				{
					_converters = new JsonConverterCollection();
				}
				return _converters;
			}
		}

		public virtual IContractResolver ContractResolver
		{
			get
			{
				return _contractResolver;
			}
			set
			{
				_contractResolver = value ?? DefaultContractResolver.Instance;
			}
		}

		public virtual StreamingContext Context
		{
			get
			{
				return _context;
			}
			set
			{
				_context = value;
			}
		}

		public virtual Formatting Formatting
		{
			get
			{
				return _formatting.GetValueOrDefault();
			}
			set
			{
				_formatting = value;
			}
		}

		public virtual DateFormatHandling DateFormatHandling
		{
			get
			{
				return _dateFormatHandling.GetValueOrDefault();
			}
			set
			{
				_dateFormatHandling = value;
			}
		}

		public virtual DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling ?? DateTimeZoneHandling.RoundtripKind;
			}
			set
			{
				_dateTimeZoneHandling = value;
			}
		}

		public virtual DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling ?? DateParseHandling.DateTime;
			}
			set
			{
				_dateParseHandling = value;
			}
		}

		public virtual FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling.GetValueOrDefault();
			}
			set
			{
				_floatParseHandling = value;
			}
		}

		public virtual FloatFormatHandling FloatFormatHandling
		{
			get
			{
				return _floatFormatHandling.GetValueOrDefault();
			}
			set
			{
				_floatFormatHandling = value;
			}
		}

		public virtual StringEscapeHandling StringEscapeHandling
		{
			get
			{
				return _stringEscapeHandling.GetValueOrDefault();
			}
			set
			{
				_stringEscapeHandling = value;
			}
		}

		public virtual string DateFormatString
		{
			get
			{
				return _dateFormatString ?? "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
			}
			set
			{
				_dateFormatString = value;
				_dateFormatStringSet = true;
			}
		}

		public virtual CultureInfo Culture
		{
			get
			{
				return _culture ?? JsonSerializerSettings.DefaultCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public virtual int? MaxDepth
		{
			get
			{
				return _maxDepth;
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
				_maxDepthSet = true;
			}
		}

		public virtual bool CheckAdditionalContent
		{
			get
			{
				return _checkAdditionalContent.GetValueOrDefault();
			}
			set
			{
				_checkAdditionalContent = value;
			}
		}

		public virtual event EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs>? Error;

		internal bool IsCheckAdditionalContentSet()
		{
			return _checkAdditionalContent.HasValue;
		}

		public JsonSerializer()
		{
			_referenceLoopHandling = ReferenceLoopHandling.Error;
			_missingMemberHandling = MissingMemberHandling.Ignore;
			_nullValueHandling = NullValueHandling.Include;
			_defaultValueHandling = DefaultValueHandling.Include;
			_objectCreationHandling = ObjectCreationHandling.Auto;
			_preserveReferencesHandling = PreserveReferencesHandling.None;
			_constructorHandling = ConstructorHandling.Default;
			_typeNameHandling = TypeNameHandling.None;
			_metadataPropertyHandling = MetadataPropertyHandling.Default;
			_context = JsonSerializerSettings.DefaultContext;
			_serializationBinder = DefaultSerializationBinder.Instance;
			_culture = JsonSerializerSettings.DefaultCulture;
			_contractResolver = DefaultContractResolver.Instance;
		}

		public static JsonSerializer Create()
		{
			return new JsonSerializer();
		}

		public static JsonSerializer Create(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = Create();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		public static JsonSerializer CreateDefault()
		{
			JsonSerializerSettings settings = JsonConvert.DefaultSettings?.Invoke();
			return Create(settings);
		}

		public static JsonSerializer CreateDefault(JsonSerializerSettings? settings)
		{
			JsonSerializer jsonSerializer = CreateDefault();
			if (settings != null)
			{
				ApplySerializerSettings(jsonSerializer, settings);
			}
			return jsonSerializer;
		}

		private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings)
		{
			if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
			{
				for (int i = 0; i < settings.Converters.Count; i++)
				{
					serializer.Converters.Insert(i, settings.Converters[i]);
				}
			}
			if (settings._typeNameHandling.HasValue)
			{
				serializer.TypeNameHandling = settings.TypeNameHandling;
			}
			if (settings._metadataPropertyHandling.HasValue)
			{
				serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling;
			}
			if (settings._typeNameAssemblyFormatHandling.HasValue)
			{
				serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling;
			}
			if (settings._preserveReferencesHandling.HasValue)
			{
				serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
			}
			if (settings._referenceLoopHandling.HasValue)
			{
				serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
			}
			if (settings._missingMemberHandling.HasValue)
			{
				serializer.MissingMemberHandling = settings.MissingMemberHandling;
			}
			if (settings._objectCreationHandling.HasValue)
			{
				serializer.ObjectCreationHandling = settings.ObjectCreationHandling;
			}
			if (settings._nullValueHandling.HasValue)
			{
				serializer.NullValueHandling = settings.NullValueHandling;
			}
			if (settings._defaultValueHandling.HasValue)
			{
				serializer.DefaultValueHandling = settings.DefaultValueHandling;
			}
			if (settings._constructorHandling.HasValue)
			{
				serializer.ConstructorHandling = settings.ConstructorHandling;
			}
			if (settings._context.HasValue)
			{
				serializer.Context = settings.Context;
			}
			if (settings._checkAdditionalContent.HasValue)
			{
				serializer._checkAdditionalContent = settings._checkAdditionalContent;
			}
			if (settings.Error != null)
			{
				serializer.Error += settings.Error;
			}
			if (settings.ContractResolver != null)
			{
				serializer.ContractResolver = settings.ContractResolver;
			}
			if (settings.ReferenceResolverProvider != null)
			{
				serializer.ReferenceResolver = settings.ReferenceResolverProvider();
			}
			if (settings.TraceWriter != null)
			{
				serializer.TraceWriter = settings.TraceWriter;
			}
			if (settings.EqualityComparer != null)
			{
				serializer.EqualityComparer = settings.EqualityComparer;
			}
			if (settings.SerializationBinder != null)
			{
				serializer.SerializationBinder = settings.SerializationBinder;
			}
			if (settings._formatting.HasValue)
			{
				serializer._formatting = settings._formatting;
			}
			if (settings._dateFormatHandling.HasValue)
			{
				serializer._dateFormatHandling = settings._dateFormatHandling;
			}
			if (settings._dateTimeZoneHandling.HasValue)
			{
				serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling;
			}
			if (settings._dateParseHandling.HasValue)
			{
				serializer._dateParseHandling = settings._dateParseHandling;
			}
			if (settings._dateFormatStringSet)
			{
				serializer._dateFormatString = settings._dateFormatString;
				serializer._dateFormatStringSet = settings._dateFormatStringSet;
			}
			if (settings._floatFormatHandling.HasValue)
			{
				serializer._floatFormatHandling = settings._floatFormatHandling;
			}
			if (settings._floatParseHandling.HasValue)
			{
				serializer._floatParseHandling = settings._floatParseHandling;
			}
			if (settings._stringEscapeHandling.HasValue)
			{
				serializer._stringEscapeHandling = settings._stringEscapeHandling;
			}
			if (settings._culture != null)
			{
				serializer._culture = settings._culture;
			}
			if (settings._maxDepthSet)
			{
				serializer._maxDepth = settings._maxDepth;
				serializer._maxDepthSet = settings._maxDepthSet;
			}
		}

		[DebuggerStepThrough]
		public void Populate(TextReader reader, object target)
		{
			Populate(new JsonTextReader(reader), target);
		}

		[DebuggerStepThrough]
		public void Populate(JsonReader reader, object target)
		{
			PopulateInternal(reader, target);
		}

		internal virtual void PopulateInternal(JsonReader reader, object target)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			ValidationUtils.ArgumentNotNull(target, "target");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			JsonSerializerInternalReader jsonSerializerInternalReader = new JsonSerializerInternalReader(this);
			jsonSerializerInternalReader.Populate(traceJsonReader ?? reader, target);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader)
		{
			return Deserialize(reader, null);
		}

		[DebuggerStepThrough]
		public object? Deserialize(TextReader reader, Type objectType)
		{
			return Deserialize(new JsonTextReader(reader), objectType);
		}

		[DebuggerStepThrough]
		public T? Deserialize<T>(JsonReader reader)
		{
			return (T)Deserialize(reader, typeof(T));
		}

		[DebuggerStepThrough]
		public object? Deserialize(JsonReader reader, Type? objectType)
		{
			return DeserializeInternal(reader, objectType);
		}

		internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(reader, "reader");
			SetupReader(reader, out CultureInfo previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string previousDateFormatString);
			TraceJsonReader traceJsonReader = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? CreateTraceJsonReader(reader) : null);
			JsonSerializerInternalReader jsonSerializerInternalReader = new JsonSerializerInternalReader(this);
			object result = jsonSerializerInternalReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
			if (traceJsonReader != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
			}
			ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
			return result;
		}

		internal void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
		{
			if (_culture != null && !_culture.Equals(reader.Culture))
			{
				previousCulture = reader.Culture;
				reader.Culture = _culture;
			}
			else
			{
				previousCulture = null;
			}
			if (_dateTimeZoneHandling.HasValue && reader.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				previousDateTimeZoneHandling = reader.DateTimeZoneHandling;
				reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			else
			{
				previousDateTimeZoneHandling = null;
			}
			if (_dateParseHandling.HasValue && reader.DateParseHandling != _dateParseHandling)
			{
				previousDateParseHandling = reader.DateParseHandling;
				reader.DateParseHandling = _dateParseHandling.GetValueOrDefault();
			}
			else
			{
				previousDateParseHandling = null;
			}
			if (_floatParseHandling.HasValue && reader.FloatParseHandling != _floatParseHandling)
			{
				previousFloatParseHandling = reader.FloatParseHandling;
				reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault();
			}
			else
			{
				previousFloatParseHandling = null;
			}
			if (_maxDepthSet && reader.MaxDepth != _maxDepth)
			{
				previousMaxDepth = reader.MaxDepth;
				reader.MaxDepth = _maxDepth;
			}
			else
			{
				previousMaxDepth = null;
			}
			if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString)
			{
				previousDateFormatString = reader.DateFormatString;
				reader.DateFormatString = _dateFormatString;
			}
			else
			{
				previousDateFormatString = null;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver defaultContractResolver)
			{
				jsonTextReader.PropertyNameTable = defaultContractResolver.GetNameTable();
			}
		}

		private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString)
		{
			if (previousCulture != null)
			{
				reader.Culture = previousCulture;
			}
			if (previousDateTimeZoneHandling.HasValue)
			{
				reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
			}
			if (previousDateParseHandling.HasValue)
			{
				reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault();
			}
			if (previousFloatParseHandling.HasValue)
			{
				reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault();
			}
			if (_maxDepthSet)
			{
				reader.MaxDepth = previousMaxDepth;
			}
			if (_dateFormatStringSet)
			{
				reader.DateFormatString = previousDateFormatString;
			}
			if (reader is JsonTextReader jsonTextReader && jsonTextReader.PropertyNameTable != null && _contractResolver is DefaultContractResolver defaultContractResolver && jsonTextReader.PropertyNameTable == defaultContractResolver.GetNameTable())
			{
				jsonTextReader.PropertyNameTable = null;
			}
		}

		public void Serialize(TextWriter textWriter, object? value)
		{
			Serialize(new JsonTextWriter(textWriter), value);
		}

		public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			SerializeInternal(jsonWriter, value, objectType);
		}

		public void Serialize(TextWriter textWriter, object? value, Type objectType)
		{
			Serialize(new JsonTextWriter(textWriter), value, objectType);
		}

		public void Serialize(JsonWriter jsonWriter, object? value)
		{
			SerializeInternal(jsonWriter, value, null);
		}

		private TraceJsonReader CreateTraceJsonReader(JsonReader reader)
		{
			TraceJsonReader traceJsonReader = new TraceJsonReader(reader);
			if (reader.TokenType != 0)
			{
				traceJsonReader.WriteCurrentToken();
			}
			return traceJsonReader;
		}

		internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType)
		{
			ValidationUtils.ArgumentNotNull(jsonWriter, "jsonWriter");
			Formatting? formatting = null;
			if (_formatting.HasValue && jsonWriter.Formatting != _formatting)
			{
				formatting = jsonWriter.Formatting;
				jsonWriter.Formatting = _formatting.GetValueOrDefault();
			}
			DateFormatHandling? dateFormatHandling = null;
			if (_dateFormatHandling.HasValue && jsonWriter.DateFormatHandling != _dateFormatHandling)
			{
				dateFormatHandling = jsonWriter.DateFormatHandling;
				jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault();
			}
			DateTimeZoneHandling? dateTimeZoneHandling = null;
			if (_dateTimeZoneHandling.HasValue && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling)
			{
				dateTimeZoneHandling = jsonWriter.DateTimeZoneHandling;
				jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
			}
			FloatFormatHandling? floatFormatHandling = null;
			if (_floatFormatHandling.HasValue && jsonWriter.FloatFormatHandling != _floatFormatHandling)
			{
				floatFormatHandling = jsonWriter.FloatFormatHandling;
				jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault();
			}
			StringEscapeHandling? stringEscapeHandling = null;
			if (_stringEscapeHandling.HasValue && jsonWriter.StringEscapeHandling != _stringEscapeHandling)
			{
				stringEscapeHandling = jsonWriter.StringEscapeHandling;
				jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault();
			}
			CultureInfo cultureInfo = null;
			if (_culture != null && !_culture.Equals(jsonWriter.Culture))
			{
				cultureInfo = jsonWriter.Culture;
				jsonWriter.Culture = _culture;
			}
			string dateFormatString = null;
			if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString)
			{
				dateFormatString = jsonWriter.DateFormatString;
				jsonWriter.DateFormatString = _dateFormatString;
			}
			TraceJsonWriter traceJsonWriter = ((TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose) ? new TraceJsonWriter(jsonWriter) : null);
			JsonSerializerInternalWriter jsonSerializerInternalWriter = new JsonSerializerInternalWriter(this);
			jsonSerializerInternalWriter.Serialize(traceJsonWriter ?? jsonWriter, value, objectType);
			if (traceJsonWriter != null)
			{
				TraceWriter.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null);
			}
			if (formatting.HasValue)
			{
				jsonWriter.Formatting = formatting.GetValueOrDefault();
			}
			if (dateFormatHandling.HasValue)
			{
				jsonWriter.DateFormatHandling = dateFormatHandling.GetValueOrDefault();
			}
			if (dateTimeZoneHandling.HasValue)
			{
				jsonWriter.DateTimeZoneHandling = dateTimeZoneHandling.GetValueOrDefault();
			}
			if (floatFormatHandling.HasValue)
			{
				jsonWriter.FloatFormatHandling = floatFormatHandling.GetValueOrDefault();
			}
			if (stringEscapeHandling.HasValue)
			{
				jsonWriter.StringEscapeHandling = stringEscapeHandling.GetValueOrDefault();
			}
			if (_dateFormatStringSet)
			{
				jsonWriter.DateFormatString = dateFormatString;
			}
			if (cultureInfo != null)
			{
				jsonWriter.Culture = cultureInfo;
			}
		}

		internal IReferenceResolver GetReferenceResolver()
		{
			if (_referenceResolver == null)
			{
				_referenceResolver = new DefaultReferenceResolver();
			}
			return _referenceResolver;
		}

		internal JsonConverter? GetMatchingConverter(Type type)
		{
			return GetMatchingConverter(_converters, type);
		}

		internal static JsonConverter? GetMatchingConverter(IList<JsonConverter>? converters, Type objectType)
		{
			ValidationUtils.ArgumentNotNull(objectType, "objectType");
			if (converters != null)
			{
				for (int i = 0; i < converters.Count; i++)
				{
					JsonConverter jsonConverter = converters[i];
					if (jsonConverter.CanConvert(objectType))
					{
						return jsonConverter;
					}
				}
			}
			return null;
		}

		internal void OnError(Newtonsoft.Json.Serialization.ErrorEventArgs e)
		{
			this.Error?.Invoke(this, e);
		}
	}
	public class JsonSerializerSettings
	{
		internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error;

		internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore;

		internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;

		internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;

		internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;

		internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;

		internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;

		internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;

		internal const MetadataPropertyHandling DefaultMetadataPropertyHandling = MetadataPropertyHandling.Default;

		internal static readonly StreamingContext DefaultContext;

		internal const Formatting DefaultFormatting = Formatting.None;

		internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;

		internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;

		internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime;

		internal const FloatParseHandling DefaultFloatParseHandling = FloatParseHandling.Double;

		internal const FloatFormatHandling DefaultFloatFormatHandling = FloatFormatHandling.String;

		internal const StringEscapeHandling DefaultStringEscapeHandling = StringEscapeHandling.Default;

		internal const TypeNameAssemblyFormatHandling DefaultTypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;

		internal static readonly CultureInfo DefaultCulture;

		internal const bool DefaultCheckAdditionalContent = false;

		internal const string DefaultDateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";

		internal const int DefaultMaxDepth = 64;

		internal Formatting? _formatting;

		internal DateFormatHandling? _dateFormatHandling;

		internal DateTimeZoneHandling? _dateTimeZoneHandling;

		internal DateParseHandling? _dateParseHandling;

		internal FloatFormatHandling? _floatFormatHandling;

		internal FloatParseHandling? _floatParseHandling;

		internal StringEscapeHandling? _stringEscapeHandling;

		internal CultureInfo? _culture;

		internal bool? _checkAdditionalContent;

		internal int? _maxDepth;

		internal bool _maxDepthSet;

		internal string? _dateFormatString;

		internal bool _dateFormatStringSet;

		internal TypeNameAssemblyFormatHandling? _typeNameAssemblyFormatHandling;

		internal DefaultValueHandling? _defaultValueHandling;

		internal PreserveReferencesHandling? _preserveReferencesHandling;

		internal NullValueHandling? _nullValueHandling;

		internal ObjectCreationHandling? _objectCreationHandling;

		internal MissingMemberHandling? _missingMemberHandling;

		internal ReferenceLoopHandling? _referenceLoopHandling;

		internal StreamingContext? _context;

		internal ConstructorHandling? _constructorHandling;

		internal TypeNameHandling? _typeNameHandling;

		internal MetadataPropertyHandling? _metadataPropertyHandling;

		public ReferenceLoopHandling ReferenceLoopHandling
		{
			get
			{
				return _referenceLoopHandling.GetValueOrDefault();
			}
			set
			{
				_referenceLoopHandling = value;
			}
		}

		public MissingMemberHandling MissingMemberHandling
		{
			get
			{
				return _missingMemberHandling.GetValueOrDefault();
			}
			set
			{
				_missingMemberHandling = value;
			}
		}

		public ObjectCreationHandling ObjectCreationHandling
		{
			get
			{
				return _objectCreationHandling.GetValueOrDefault();
			}
			set
			{
				_objectCreationHandling = value;
			}
		}

		public NullValueHandling NullValueHandling
		{
			get
			{
				return _nullValueHandling.GetValueOrDefault();
			}
			set
			{
				_nullValueHandling = value;
			}
		}

		public DefaultValueHandling DefaultValueHandling
		{
			get
			{
				return _defaultValueHandling.GetValueOrDefault();
			}
			set
			{
				_defaultValueHandling = value;
			}
		}

		public IList<JsonConverter> Converters { get; set; }

		public PreserveReferencesHandling PreserveReferencesHandling
		{
			get
			{
				return _preserveReferencesHandling.GetValueOrDefault();
			}
			set
			{
				_preserveReferencesHandling = value;
			}
		}

		public TypeNameHandling TypeNameHandling
		{
			get
			{
				return _typeNameHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameHandling = value;
			}
		}

		public MetadataPropertyHandling MetadataPropertyHandling
		{
			get
			{
				return _metadataPropertyHandling.GetValueOrDefault();
			}
			set
			{
				_metadataPropertyHandling = value;
			}
		}

		[Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
		public FormatterAssemblyStyle TypeNameAssemblyFormat
		{
			get
			{
				return (FormatterAssemblyStyle)TypeNameAssemblyFormatHandling;
			}
			set
			{
				TypeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
			}
		}

		public TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
		{
			get
			{
				return _typeNameAssemblyFormatHandling.GetValueOrDefault();
			}
			set
			{
				_typeNameAssemblyFormatHandling = value;
			}
		}

		public ConstructorHandling ConstructorHandling
		{
			get
			{
				return _constructorHandling.GetValueOrDefault();
			}
			set
			{
				_constructorHandling = value;
			}
		}

		public IContractResolver? ContractResolver { get; set; }

		public IEqualityComparer? EqualityComparer { get; set; }

		[Obsolete("ReferenceResolver property is obsolete. Use the ReferenceResolverProvider property to set the IReferenceResolver: settings.ReferenceResolverProvider = () => resolver")]
		public IReferenceResolver? ReferenceResolver
		{
			get
			{
				return ReferenceResolverProvider?.Invoke();
			}
			set
			{
				IReferenceResolver value2 = value;
				ReferenceResolverProvider = ((value2 != null) ? ((Func<IReferenceResolver>)(() => value2)) : null);
			}
		}

		public Func<IReferenceResolver?>? ReferenceResolverProvider { get; set; }

		public ITraceWriter? TraceWriter { get; set; }

		[Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
		public SerializationBinder? Binder
		{
			get
			{
				if (SerializationBinder == null)
				{
					return null;
				}
				if (SerializationBinder is SerializationBinderAdapter serializationBinderAdapter)
				{
					return serializationBinderAdapter.SerializationBinder;
				}
				throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
			}
			set
			{
				SerializationBinder = ((value == null) ? null : new SerializationBinderAdapter(value));
			}
		}

		public ISerializationBinder? SerializationBinder { get; set; }

		public EventHandler<Newtonsoft.Json.Serialization.ErrorEventArgs>? Error { get; set; }

		public StreamingContext Context
		{
			get
			{
				return _context ?? DefaultContext;
			}
			set
			{
				_context = value;
			}
		}

		public string DateFormatString
		{
			get
			{
				return _dateFormatString ?? "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
			}
			set
			{
				_dateFormatString = value;
				_dateFormatStringSet = true;
			}
		}

		public int? MaxDepth
		{
			get
			{
				return _maxDepthSet ? _maxDepth : new int?(64);
			}
			set
			{
				if (value <= 0)
				{
					throw new ArgumentException("Value must be positive.", "value");
				}
				_maxDepth = value;
				_maxDepthSet = true;
			}
		}

		public Formatting Formatting
		{
			get
			{
				return _formatting.GetValueOrDefault();
			}
			set
			{
				_formatting = value;
			}
		}

		public DateFormatHandling DateFormatHandling
		{
			get
			{
				return _dateFormatHandling.GetValueOrDefault();
			}
			set
			{
				_dateFormatHandling = value;
			}
		}

		public DateTimeZoneHandling DateTimeZoneHandling
		{
			get
			{
				return _dateTimeZoneHandling ?? DateTimeZoneHandling.RoundtripKind;
			}
			set
			{
				_dateTimeZoneHandling = value;
			}
		}

		public DateParseHandling DateParseHandling
		{
			get
			{
				return _dateParseHandling ?? DateParseHandling.DateTime;
			}
			set
			{
				_dateParseHandling = value;
			}
		}

		public FloatFormatHandling FloatFormatHandling
		{
			get
			{
				return _floatFormatHandling.GetValueOrDefault();
			}
			set
			{
				_floatFormatHandling = value;
			}
		}

		public FloatParseHandling FloatParseHandling
		{
			get
			{
				return _floatParseHandling.GetValueOrDefault();
			}
			set
			{
				_floatParseHandling = value;
			}
		}

		public StringEscapeHandling StringEscapeHandling
		{
			get
			{
				return _stringEscapeHandling.GetValueOrDefault();
			}
			set
			{
				_stringEscapeHandling = value;
			}
		}

		public CultureInfo Culture
		{
			get
			{
				return _culture ?? DefaultCulture;
			}
			set
			{
				_culture = value;
			}
		}

		public bool CheckAdditionalContent
		{
			get
			{
				return _checkAdditionalContent.GetValueOrDefault();
			}
			set
			{
				_checkAdditionalContent = value;
			}
		}

		static JsonSerializerSettings()
		{
			DefaultContext = default(StreamingContext);
			DefaultCulture = CultureInfo.InvariantCulture;
		}

		[DebuggerStepThrough]
		public JsonSerializerSettings()
		{
			Converters = new List<JsonConverter>();
		}
	}
	internal enum ReadType
	{
		Read,
		ReadAsInt32,
		ReadAsInt64,
		ReadAsBytes,
		ReadAsString,
		ReadAsDecimal,
		ReadAsDateTime,
		ReadAsDateTimeOffset,
		ReadAsDouble,
		ReadAsBoolean
	}
	public class JsonTextReader : JsonReader, IJsonLineInfo
	{
		private const char UnicodeReplacementChar = '\ufffd';

		private readonly TextReader _reader;

		private char[]? _chars;

		private int _charsUsed;

		private int _charPos;

		private int _lineStartPos;

		private int _lineNumber;

		private bool _isEndOfFile;

		private StringBuffer _stringBuffer;

		private StringReference _stringReference;

		private IArrayPool<char>? _arrayPool;

		internal int LargeBufferLength { get; set; } = 1073741823;


		internal char[]? CharBuffer
		{
			get
			{
				return _chars;
			}
			set
			{
				_chars = value;
			}
		}

		internal int CharPos => _charPos;

		public JsonNameTable? PropertyNameTable { get; set; }

		public IArrayPool<char>? ArrayPool
		{
			get
			{
				return _arrayPool;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("value");
				}
				_arrayPool = value;
			}
		}

		public int LineNumber
		{
			get
			{
				if (base.CurrentState == State.Start && LinePosition == 0 && TokenType != JsonToken.Comment)
				{
					return 0;
				}
				return _lineNumber;
			}
		}

		public int LinePosition => _charPos - _lineStartPos;

		public JsonTextReader(TextReader reader)
		{
			if (reader == null)
			{
				throw new ArgumentNullException("reader");
			}
			_reader = reader;
			_lineNumber = 1;
		}

		private void EnsureBufferNotEmpty()
		{
			if (_stringBuffer.IsEmpty)
			{
				_stringBuffer = new StringBuffer(_arrayPool, 1024);
			}
		}

		private void SetNewLine(bool hasNextChar)
		{
			MiscellaneousUtils.Assert(_chars != null);
			if (hasNextChar && _chars[_charPos] == '\n')
			{
				_charPos++;
			}
			OnNewLine(_charPos);
		}

		private void OnNewLine(int pos)
		{
			_lineNumber++;
			_lineStartPos = pos;
		}

		private void ParseString(char quote, ReadType readType)
		{
			_charPos++;
			ShiftBufferIfNeeded();
			ReadStringIntoBuffer(quote);
			ParseReadString(quote, readType);
		}

		private void ParseReadString(char quote, ReadType readType)
		{
			SetPostValueState(updateIndex: true);
			switch (readType)
			{
			case ReadType.ReadAsBytes:
			{
				Guid g;
				byte[] value2 = ((_stringReference.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((_stringReference.Length != 36 || !ConvertUtils.TryConvertGuid(_stringReference.ToString(), out g)) ? Convert.FromBase64CharArray(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length) : g.ToByteArray()));
				SetToken(JsonToken.Bytes, value2, updateIndex: false);
				return;
			}
			case ReadType.ReadAsString:
			{
				string value = _stringReference.ToString();
				SetToken(JsonToken.String, value, updateIndex: false);
				_quoteChar = quote;
				return;
			}
			case ReadType.ReadAsInt32:
			case ReadType.ReadAsDecimal:
			case ReadType.ReadAsBoolean:
				return;
			}
			if (_dateParseHandling != 0)
			{
				DateTimeOffset dt2;
				if (readType switch
				{
					ReadType.ReadAsDateTime => 1, 
					ReadType.ReadAsDateTimeOffset => 2, 
					_ => (int)_dateParseHandling, 
				} == 1)
				{
					if (DateTimeUtils.TryParseDateTime(_stringReference, base.DateTimeZoneHandling, base.DateFormatString, base.Culture, out var dt))
					{
						SetToken(JsonToken.Date, dt, updateIndex: false);
						return;
					}
				}
				else if (DateTimeUtils.TryParseDateTimeOffset(_stringReference, base.DateFormatString, base.Culture, out dt2))
				{
					SetToken(JsonToken.Date, dt2, updateIndex: false);
					return;
				}
			}
			SetToken(JsonToken.String, _stringReference.ToString(), updateIndex: false);
			_quoteChar = quote;
		}

		private static void BlockCopyChars(char[] src, int srcOffset, char[] dst, int dstOffset, int count)
		{
			Buffer.BlockCopy(src, srcOffset * 2, dst, dstOffset * 

PikunikuAPMod.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.Colors;
using Archipelago.MultiClient.Net.Converters;
using Archipelago.MultiClient.Net.Enums;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using Pikuniku.Achievements;
using Pikuniku.Drawing;
using Pikuniku.Persistence;
using Rewired;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("PikunikuAPMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+769ef2132f199e35f20c8a16e601f4740d45f8b9")]
[assembly: AssemblyProduct("PikunikuAPMod")]
[assembly: AssemblyTitle("PikunikuAPMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PikunikuAPMod
{
	public class APConnectionPanel : UI_MenuPanel
	{
		private class NavVisual
		{
			public Selectable Selectable;

			public RectTransform Rect;

			public Image Background;

			public Outline Outline;

			public Shadow Shadow;

			public Vector2 CurrentOffset = Vector2.zero;

			public Vector2 CurrentShadowDist = Vector2.zero;

			public float CurrentShadowAlpha;
		}

		internal UI_MenuPanel_Aventure AventurePanel;

		private TMP_InputField _hostnameField;

		private TMP_InputField _portField;

		private TMP_InputField _slotField;

		private TMP_InputField _passwordField;

		private TextMeshProUGUI _statusText;

		private TMP_FontAsset _gameFont;

		private Sprite _bgSprite;

		private NavVisual[] _nav;

		private int _navIndex;

		private static readonly Color NormalBg = Color.white;

		private static readonly Color NormalOutline = Color.black;

		private static readonly Vector2 NormalOutlineDist = new Vector2(4f, -4f);

		private static readonly Color SolidShadowColor = new Color(0f, 0f, 0f, 1f);

		private static readonly Vector2 SolidShadowDist = new Vector2(8f, -8f);

		private static readonly Vector2 SelectedOffset = new Vector2(-4f, 4f);

		public static APConnectionPanel Instance { get; private set; }

		public static APConnectionPanel CreateFor(UI_PauseMenu pauseMenu, UI_MenuPanel_Aventure aventurePanel)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Invalid comparison between Unknown and I4
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Invalid comparison between Unknown and I4
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Expected O, but got Unknown
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Expected O, but got Unknown
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Expected O, but got Unknown
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Expected O, but got Unknown
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Expected O, but got Unknown
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Expected O, but got Unknown
			//IL_01d1: 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_01eb: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Instance != (Object)null)
			{
				return Instance;
			}
			Transform parent = ((Transform)((UI_MenuPanel)aventurePanel).selfRect).parent;
			GameObject val = new GameObject("APConnectionPanel");
			RectTransform val2 = val.AddComponent<RectTransform>();
			((Transform)val2).SetParent(parent, false);
			RectTransform selfRect = ((UI_MenuPanel)aventurePanel).selfRect;
			RectTransform component = ((Component)parent).GetComponent<RectTransform>();
			float num;
			if ((Object)(object)component != (Object)null)
			{
				Rect rect = component.rect;
				if (((Rect)(ref rect)).height > 1f)
				{
					rect = component.rect;
					num = ((Rect)(ref rect)).height;
					goto IL_008e;
				}
			}
			num = 720f;
			goto IL_008e;
			IL_008e:
			float num2 = num;
			val2.anchorMin = new Vector2(selfRect.anchorMin.x, 0.5f);
			val2.anchorMax = new Vector2(selfRect.anchorMax.x, 0.5f);
			val2.pivot = selfRect.pivot;
			val2.sizeDelta = new Vector2(selfRect.sizeDelta.x, num2);
			val2.anchoredPosition = Vector2.zero;
			((Transform)val2).localScale = ((Transform)selfRect).localScale;
			((Transform)val2).localPosition = ((Transform)selfRect).localPosition;
			((Transform)val2).localRotation = ((Transform)selfRect).localRotation;
			val.layer = ((Component)aventurePanel).gameObject.layer;
			Canvas selfCanvas = ((UI_MenuPanel)aventurePanel).selfCanvas;
			Canvas val3 = val.AddComponent<Canvas>();
			val3.renderMode = selfCanvas.renderMode;
			val3.sortingOrder = selfCanvas.sortingOrder;
			val3.sortingLayerID = selfCanvas.sortingLayerID;
			val3.overrideSorting = selfCanvas.overrideSorting;
			val3.pixelPerfect = selfCanvas.pixelPerfect;
			if ((int)selfCanvas.renderMode == 1 || (int)selfCanvas.renderMode == 2)
			{
				val3.worldCamera = selfCanvas.worldCamera;
			}
			((Behaviour)val3).enabled = false;
			CanvasScaler component2 = ((Component)((UI_MenuPanel)aventurePanel).selfCanvas).GetComponent<CanvasScaler>();
			if ((Object)(object)component2 != (Object)null)
			{
				CanvasScaler obj = val.AddComponent<CanvasScaler>();
				obj.uiScaleMode = component2.uiScaleMode;
				obj.referenceResolution = component2.referenceResolution;
				obj.screenMatchMode = component2.screenMatchMode;
				obj.matchWidthOrHeight = component2.matchWidthOrHeight;
				obj.referencePixelsPerUnit = component2.referencePixelsPerUnit;
			}
			val.AddComponent<GraphicRaycaster>();
			CanvasGroup val4 = val.AddComponent<CanvasGroup>();
			val4.interactable = false;
			APConnectionPanel panel = val.AddComponent<APConnectionPanel>();
			((UI_MenuPanel)panel).manager = pauseMenu;
			((UI_MenuPanel)panel).selfRect = val2;
			((UI_MenuPanel)panel).selfCanvas = val3;
			((UI_MenuPanel)panel).canvasGroup = val4;
			((UI_MenuPanel)panel).FullGameObject = val;
			((UI_MenuPanel)panel).allowBackButton = true;
			panel.AventurePanel = aventurePanel;
			((UI_MenuPanel)panel).OnBackButton = new UnityEvent();
			((UI_MenuPanel)panel).OnPreEnableEvent = new UnityEvent();
			((UI_MenuPanel)panel).OnEnableEvent = new UnityEvent();
			((UI_MenuPanel)panel).OnDisableEvent = new UnityEvent();
			((UI_MenuPanel)panel).OnBackButton.AddListener((UnityAction)delegate
			{
				pauseMenu.SwitchToPanelFromBack((UI_MenuPanel)(object)panel);
			});
			((UI_MenuPanel)panel).OnPreEnableEvent.AddListener((UnityAction)delegate
			{
				if ((Object)(object)panel._statusText != (Object)null)
				{
					((TMP_Text)panel._statusText).text = string.Empty;
				}
			});
			panel.GrabGameStyle(aventurePanel);
			panel.BuildUI();
			ArchipelagoHandler archipelagoHandler = PikunikuAPMod.ArchipelagoHandler;
			if ((Object)(object)archipelagoHandler != (Object)null)
			{
				archipelagoHandler.OnConnected += panel.OnConnected;
				archipelagoHandler.OnConnectionFailed += panel.OnConnectionFailed;
			}
			Instance = panel;
			Log.Info("APConnectionPanel created as sibling of adventure panel.");
			return panel;
		}

		private void OnDestroy()
		{
			ArchipelagoHandler archipelagoHandler = PikunikuAPMod.ArchipelagoHandler;
			if ((Object)(object)archipelagoHandler != (Object)null)
			{
				archipelagoHandler.OnConnected -= OnConnected;
				archipelagoHandler.OnConnectionFailed -= OnConnectionFailed;
			}
			Instance = null;
		}

		public override void CustomPanelUpdate()
		{
			UpdateAnimation();
			if (_nav == null || _nav.Length == 0)
			{
				return;
			}
			SyncIndexFromEventSystem();
			bool flag = Input.GetKeyDown((KeyCode)274) || RewiredNavDown();
			bool flag2 = Input.GetKeyDown((KeyCode)273) || RewiredNavUp();
			if (Input.GetKeyDown((KeyCode)9))
			{
				if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303))
				{
					flag2 = true;
				}
				else
				{
					flag = true;
				}
			}
			if (flag)
			{
				Move(1);
			}
			else if (flag2)
			{
				Move(-1);
			}
			ApplyHighlight();
		}

		private void Move(int delta)
		{
			int num = _nav.Length;
			int num2 = _navIndex;
			for (int i = 0; i < num; i++)
			{
				num2 = (num2 + delta + num) % num;
				if ((Object)(object)_nav[num2]?.Selectable != (Object)null && _nav[num2].Selectable.IsInteractable())
				{
					break;
				}
			}
			SelectIndex(num2);
		}

		private void SelectIndex(int i)
		{
			if (_nav == null || i < 0 || i >= _nav.Length)
			{
				return;
			}
			NavVisual[] nav = _nav;
			for (int j = 0; j < nav.Length; j++)
			{
				Selectable obj = nav[j]?.Selectable;
				TMP_InputField val = (TMP_InputField)(object)((obj is TMP_InputField) ? obj : null);
				if (val != null && val.isFocused)
				{
					val.DeactivateInputField();
				}
			}
			_navIndex = i;
			Selectable selectable = _nav[i].Selectable;
			if ((Object)(object)EventSystem.current != (Object)null)
			{
				EventSystem.current.SetSelectedGameObject(((Component)selectable).gameObject);
			}
			TMP_InputField val2 = (TMP_InputField)(object)((selectable is TMP_InputField) ? selectable : null);
			if (val2 != null)
			{
				val2.ActivateInputField();
				val2.MoveTextEnd(false);
			}
			ApplyHighlight();
		}

		private void SyncIndexFromEventSystem()
		{
			GameObject val = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			for (int i = 0; i < _nav.Length; i++)
			{
				if ((Object)(object)_nav[i]?.Selectable != (Object)null && (Object)(object)((Component)_nav[i].Selectable).gameObject == (Object)(object)val)
				{
					_navIndex = i;
					break;
				}
			}
		}

		private void ApplyHighlight()
		{
		}

		private void UpdateAnimation()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			if (_nav == null)
			{
				return;
			}
			float unscaledDeltaTime = Time.unscaledDeltaTime;
			float num = 60f;
			float num2 = 120f;
			float num3 = 10f;
			for (int i = 0; i < _nav.Length; i++)
			{
				NavVisual navVisual = _nav[i];
				if (navVisual == null)
				{
					continue;
				}
				bool num4 = i == _navIndex;
				Vector2 val = (num4 ? SelectedOffset : Vector2.zero);
				Vector2 val2 = (num4 ? SolidShadowDist : Vector2.zero);
				float num5 = (num4 ? 1f : 0f);
				navVisual.CurrentOffset = Vector2.MoveTowards(navVisual.CurrentOffset, val, unscaledDeltaTime * num);
				navVisual.CurrentShadowDist = Vector2.MoveTowards(navVisual.CurrentShadowDist, val2, unscaledDeltaTime * num2);
				navVisual.CurrentShadowAlpha = Mathf.MoveTowards(navVisual.CurrentShadowAlpha, num5, unscaledDeltaTime * num3);
				if ((Object)(object)navVisual.Rect != (Object)null)
				{
					navVisual.Rect.anchoredPosition = navVisual.CurrentOffset;
					((Transform)navVisual.Rect).localScale = Vector3.one;
				}
				if ((Object)(object)navVisual.Shadow != (Object)null)
				{
					bool flag = navVisual.CurrentShadowAlpha > 0.01f;
					((Behaviour)navVisual.Shadow).enabled = flag;
					if (flag)
					{
						Color solidShadowColor = SolidShadowColor;
						solidShadowColor.a = navVisual.CurrentShadowAlpha;
						navVisual.Shadow.effectColor = solidShadowColor;
						navVisual.Shadow.effectDistance = navVisual.CurrentShadowDist;
					}
				}
				if ((Object)(object)navVisual.Outline != (Object)null)
				{
					((Shadow)navVisual.Outline).effectColor = NormalOutline;
					((Shadow)navVisual.Outline).effectDistance = NormalOutlineDist;
					((Behaviour)navVisual.Outline).enabled = true;
				}
				if ((Object)(object)navVisual.Background != (Object)null)
				{
					((Graphic)navVisual.Background).color = NormalBg;
				}
			}
		}

		private static NavVisual BuildNavVisual(Selectable sel)
		{
			GameObject gameObject = ((Component)sel).gameObject;
			NavVisual navVisual = new NavVisual
			{
				Selectable = sel,
				Rect = gameObject.GetComponent<RectTransform>(),
				Background = gameObject.GetComponent<Image>(),
				Outline = gameObject.GetComponent<Outline>()
			};
			Shadow[] components = gameObject.GetComponents<Shadow>();
			foreach (Shadow val in components)
			{
				if (!(val is Outline))
				{
					navVisual.Shadow = val;
					break;
				}
			}
			return navVisual;
		}

		private void WireSubmitAdvance(TMP_InputField field, int indexOfField)
		{
			((UnityEvent<string>)(object)field.onSubmit).AddListener((UnityAction<string>)delegate
			{
				SelectIndex(Mathf.Min(indexOfField + 1, _nav.Length - 1));
			});
		}

		private static Player GetRewiredPlayer()
		{
			if ((Object)(object)PlayerManager.S == (Object)null)
			{
				return null;
			}
			PlayerClass player = PlayerManager.S.GetPlayer(0);
			if (player == null)
			{
				return null;
			}
			return player.GetRewiredPlayer();
		}

		private static bool RewiredNavUp()
		{
			Player rewiredPlayer = GetRewiredPlayer();
			if (rewiredPlayer != null)
			{
				return rewiredPlayer.GetButtonDown("UIVertical");
			}
			return false;
		}

		private static bool RewiredNavDown()
		{
			Player rewiredPlayer = GetRewiredPlayer();
			if (rewiredPlayer != null)
			{
				return rewiredPlayer.GetNegativeButtonDown("UIVertical");
			}
			return false;
		}

		private void OnConnected()
		{
			if ((Object)(object)AventurePanel != (Object)null)
			{
				AventurePanel.hasCheckedForAdventure = false;
				AventurePanel.CheckMainStory();
			}
			base.manager.SwitchToPanel((UI_MenuPanel)(object)AventurePanel);
		}

		private void OnConnectionFailed(string error)
		{
			if ((Object)(object)_statusText != (Object)null)
			{
				((TMP_Text)_statusText).text = "Failed: " + error;
			}
		}

		private void GrabGameStyle(UI_MenuPanel_Aventure aventurePanel)
		{
			TextMeshProUGUI componentInChildren = ((Component)((UI_MenuPanel)aventurePanel).selfCanvas).GetComponentInChildren<TextMeshProUGUI>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				_gameFont = ((TMP_Text)componentInChildren).font;
			}
			UI_Button[] array = Resources.FindObjectsOfTypeAll<UI_Button>();
			foreach (UI_Button val in array)
			{
				Image img_background = val.img_background;
				if ((Object)(object)((img_background != null) ? img_background.sprite : null) != (Object)null)
				{
					_bgSprite = val.img_background.sprite;
					break;
				}
			}
			Log.Info("APConnectionPanel style: font=" + (((Object)(object)_gameFont != (Object)null) ? ((Object)_gameFont).name : "null") + ", sprite=" + (((Object)(object)_bgSprite != (Object)null) ? ((Object)_bgSprite).name : "null"));
		}

		private void BuildUI()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			LastConnectionInfo lastConnectionInfo = FileWriter.ReadLastConnection();
			string defaultValue = Fallback(lastConnectionInfo?.Host, "archipelago.gg");
			string defaultValue2 = Fallback(lastConnectionInfo?.Port, "38281");
			string defaultValue3 = Fallback(lastConnectionInfo?.SlotName, "");
			string defaultValue4 = lastConnectionInfo?.Password ?? "";
			GameObject val = MakeRect("Container", ((Component)this).transform);
			RectTransform component = val.GetComponent<RectTransform>();
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			component.pivot = val2;
			Vector2 anchorMin = (component.anchorMax = val2);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(0f, 15f);
			component.sizeDelta = new Vector2(560f, 660f);
			VerticalLayoutGroup obj = val.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).childAlignment = (TextAnchor)1;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 10f;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			((LayoutGroup)obj).padding = new RectOffset(10, 10, 10, 10);
			AddSpacer(val.transform, 15f);
			AddTitle(val.transform, "Archipelago");
			AddSpacer(val.transform, 5f);
			AddHorizontalLine(val.transform, 8f);
			AddSpacer(val.transform, 10f);
			_hostnameField = AddInputRow(val.transform, "Host", defaultValue);
			_portField = AddInputRow(val.transform, "Port", defaultValue2);
			_slotField = AddInputRow(val.transform, "Slot Name", defaultValue3);
			_passwordField = AddInputRow(val.transform, "Password", defaultValue4, isPassword: true);
			AddSpacer(val.transform, 25f);
			Button val4 = AddConnectButton(val.transform);
			_statusText = AddStatusLabel(val.transform);
			Selectable[] array = (Selectable[])(object)new Selectable[5]
			{
				(Selectable)_hostnameField,
				(Selectable)_portField,
				(Selectable)_slotField,
				(Selectable)_passwordField,
				(Selectable)val4
			};
			_nav = new NavVisual[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				_nav[i] = BuildNavVisual(array[i]);
			}
			NavVisual[] nav = _nav;
			foreach (NavVisual navVisual in nav)
			{
				Navigation navigation = navVisual.Selectable.navigation;
				((Navigation)(ref navigation)).mode = (Mode)0;
				navVisual.Selectable.navigation = navigation;
				navVisual.Selectable.transition = (Transition)0;
				if ((Object)(object)navVisual.Shadow != (Object)null)
				{
					((Behaviour)navVisual.Shadow).enabled = false;
				}
			}
			WireSubmitAdvance(_hostnameField, 0);
			WireSubmitAdvance(_portField, 1);
			WireSubmitAdvance(_slotField, 2);
			WireSubmitAdvance(_passwordField, 3);
			base.toSelectFirst = ((Component)_hostnameField).gameObject;
			_navIndex = 0;
			ApplyHighlight();
		}

		private void AddTitle(Transform parent, string text)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			GameObject obj = MakeRect("Title", parent);
			TextMeshProUGUI val = obj.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val).text = text;
			((TMP_Text)val).fontSize = 65f;
			((Graphic)val).color = Color.black;
			((TMP_Text)val).fontStyle = (FontStyles)0;
			((TMP_Text)val).alignment = (TextAlignmentOptions)1028;
			ApplyFont(val);
			Shadow obj2 = obj.AddComponent<Shadow>();
			obj2.effectColor = new Color(1f, 1f, 1f, 0.8f);
			obj2.effectDistance = new Vector2(2f, -2f);
			obj.AddComponent<LayoutElement>().preferredHeight = 65f;
		}

		private TMP_InputField AddInputRow(Transform parent, string label, string defaultValue, bool isPassword = false)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = MakeRect("Row_" + label, parent);
			VerticalLayoutGroup obj = val.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).childAlignment = (TextAnchor)0;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 2f;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			val.AddComponent<LayoutElement>().preferredHeight = 90f;
			GameObject obj2 = MakeRect("Label_" + label, val.transform);
			TextMeshProUGUI val2 = obj2.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val2).text = label;
			((TMP_Text)val2).fontSize = 30f;
			((Graphic)val2).color = Color.black;
			((TMP_Text)val2).alignment = (TextAlignmentOptions)513;
			ApplyFont(val2);
			obj2.AddComponent<LayoutElement>().preferredHeight = 30f;
			GameObject val3 = MakeRect("FieldWrapper_" + label, val.transform);
			val3.AddComponent<LayoutElement>().preferredHeight = 52f;
			GameObject val4 = MakeRect("Field_" + label, val3.transform);
			Image val5 = val4.AddComponent<Image>();
			((Graphic)val5).color = Color.white;
			if ((Object)(object)_bgSprite != (Object)null)
			{
				val5.sprite = _bgSprite;
				val5.type = (Type)1;
			}
			((Behaviour)val4.AddComponent<Shadow>()).enabled = false;
			Outline obj3 = val4.AddComponent<Outline>();
			((Shadow)obj3).effectColor = Color.black;
			((Shadow)obj3).effectDistance = new Vector2(4f, -4f);
			RectTransform component = val4.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.3f, 0f);
			component.anchorMax = Vector2.one;
			component.sizeDelta = Vector2.zero;
			GameObject val6 = MakeRect("Viewport", val4.transform);
			RectTransform component2 = val6.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = new Vector2(12f, 6f);
			component2.offsetMax = new Vector2(-12f, -6f);
			val6.AddComponent<RectMask2D>();
			GameObject obj4 = MakeRect("Text", val6.transform);
			TextMeshProUGUI val7 = obj4.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val7).fontSize = 26f;
			((Graphic)val7).color = Color.black;
			((TMP_Text)val7).alignment = (TextAlignmentOptions)513;
			ApplyFont(val7);
			FillParent(obj4.GetComponent<RectTransform>());
			GameObject obj5 = MakeRect("Placeholder", val6.transform);
			TextMeshProUGUI val8 = obj5.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val8).text = label.ToLower() + "...";
			((TMP_Text)val8).fontSize = 26f;
			((Graphic)val8).color = new Color(0.4f, 0.4f, 0.4f, 0.8f);
			((TMP_Text)val8).fontStyle = (FontStyles)2;
			((TMP_Text)val8).alignment = (TextAlignmentOptions)513;
			ApplyFont(val8);
			FillParent(obj5.GetComponent<RectTransform>());
			TMP_InputField val9 = val4.AddComponent<TMP_InputField>();
			val9.textViewport = component2;
			val9.textComponent = (TMP_Text)(object)val7;
			val9.placeholder = (Graphic)(object)val8;
			val9.text = defaultValue;
			val9.caretColor = Color.black;
			val9.selectionColor = new Color(0.3f, 0.6f, 1f, 0.4f);
			if (isPassword)
			{
				val9.inputType = (InputType)2;
			}
			return val9;
		}

		private Button AddConnectButton(Transform parent)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			GameObject val = MakeRect("ButtonWrapper_Connect", parent);
			val.AddComponent<LayoutElement>().preferredHeight = 65f;
			GameObject val2 = MakeRect("Button_Connect", val.transform);
			RectTransform component = val2.GetComponent<RectTransform>();
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.sizeDelta = Vector2.zero;
			Image val3 = val2.AddComponent<Image>();
			((Graphic)val3).color = Color.white;
			if ((Object)(object)_bgSprite != (Object)null)
			{
				val3.sprite = _bgSprite;
				val3.type = (Type)1;
			}
			Outline obj = val2.AddComponent<Outline>();
			((Shadow)obj).effectColor = Color.black;
			((Shadow)obj).effectDistance = new Vector2(4f, -4f);
			Shadow obj2 = val2.AddComponent<Shadow>();
			obj2.effectColor = new Color(0f, 0f, 0f, 0.25f);
			obj2.effectDistance = new Vector2(3f, -3f);
			GameObject obj3 = MakeRect("Label", val2.transform);
			TextMeshProUGUI val4 = obj3.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val4).text = "Connect";
			((TMP_Text)val4).fontSize = 30f;
			((Graphic)val4).color = Color.black;
			((TMP_Text)val4).fontStyle = (FontStyles)0;
			((TMP_Text)val4).alignment = (TextAlignmentOptions)514;
			ApplyFont(val4);
			FillParent(obj3.GetComponent<RectTransform>());
			val2.AddComponent<LayoutElement>().preferredHeight = 65f;
			Button obj4 = val2.AddComponent<Button>();
			((UnityEvent)obj4.onClick).AddListener(new UnityAction(OnConnectClicked));
			return obj4;
		}

		private TextMeshProUGUI AddStatusLabel(Transform parent)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = MakeRect("Status", parent);
			TextMeshProUGUI val = obj.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val).text = string.Empty;
			((TMP_Text)val).fontSize = 20f;
			((Graphic)val).color = new Color(0.75f, 0.1f, 0.1f);
			((TMP_Text)val).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val).enableWordWrapping = true;
			ApplyFont(val);
			obj.AddComponent<LayoutElement>().preferredHeight = 55f;
			return val;
		}

		private void AddSpacer(Transform parent, float height)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = MakeRect("Spacer", parent);
			Image obj2 = obj.AddComponent<Image>();
			((Graphic)obj2).color = Color.clear;
			((Graphic)obj2).raycastTarget = false;
			LayoutElement obj3 = obj.AddComponent<LayoutElement>();
			obj3.preferredHeight = height;
			obj3.minHeight = height;
		}

		private void AddHorizontalLine(Transform parent, float thickness, float widthPadding = 0f)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = MakeRect("Line", parent);
			((Graphic)val.AddComponent<Image>()).color = Color.black;
			LayoutElement obj = val.AddComponent<LayoutElement>();
			obj.preferredHeight = thickness;
			obj.minHeight = thickness;
			if (widthPadding > 0f)
			{
				val.GetComponent<RectTransform>();
			}
		}

		private static GameObject MakeRect(string name, Transform parent)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.AddComponent<RectTransform>();
			val.transform.SetParent(parent, false);
			return val;
		}

		private static void FillParent(RectTransform rt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			Vector2 offsetMin = (rt.offsetMax = Vector2.zero);
			rt.offsetMin = offsetMin;
		}

		private void ApplyFont(TextMeshProUGUI tmp)
		{
			if ((Object)(object)_gameFont != (Object)null)
			{
				((TMP_Text)tmp).font = _gameFont;
			}
		}

		private static string Fallback(string value, string fallback)
		{
			if (!string.IsNullOrEmpty(value))
			{
				return value;
			}
			return fallback;
		}

		private void OnConnectClicked()
		{
			string text = _hostnameField.text.Trim();
			string s = _portField.text.Trim();
			string text2 = _slotField.text.Trim();
			string text3 = _passwordField.text;
			if (string.IsNullOrEmpty(text2))
			{
				((TMP_Text)_statusText).text = "Enter a slot name!";
				return;
			}
			if (!int.TryParse(s, out var result))
			{
				result = 38281;
			}
			((TMP_Text)_statusText).text = "Connecting…";
			try
			{
				ArchipelagoHandler archipelagoHandler = PikunikuAPMod.ArchipelagoHandler;
				archipelagoHandler.CreateSession(text, result, text2, text3);
				archipelagoHandler.Connect();
				FileWriter.WriteLastConnection(text, result, text2, text3);
			}
			catch (Exception ex)
			{
				((TMP_Text)_statusText).text = "Error: " + ex.Message;
				Log.Error($"Connect failed: {ex}");
			}
		}
	}
	public static class Scenes
	{
		public const string TitleScreen = "00_TITLESCREEN";

		public const string Prologue = "66_PROLOGUE";

		public const string MountainVillage = "02_MOUNTAINVILLAGE";

		public const string ValleyRoad = "02.1_MOUNTAINVILLAGETOFOREST";

		public const string MountainTemple = "02.2_MOUNTAIN_TEMPLE";

		public const string MountainBoss = "02.3_MOUNTAIN_ROBOTBOSS";

		public const string MountainMetro = "02.4_MOUNTAIN_METRO";

		public const string Forest = "03_FOREST";

		public const string ForestDanceBattle = "03.1_FOREST_DANCEBATTLE";

		public const string ForestTemple = "03.2_FOREST_TEMPLE";

		public const string ForestBoss = "03.3_FOREST_ROBOTBOSS";

		public const string ForestMetro = "03.4_FOREST_METRO";

		public const string ForestTartineZone = "03.5_FOREST_TARTINEZONE";

		public const string Lake = "04.1_LAKE";

		public const string Mine = "04_MINE";

		public const string LakeBoss = "04.2_LAKE_ROBOTBOSS";

		public const string HQ = "05_HQ";

		public const string HQFinalBoss = "05.1_HQ_FINALBOSS";

		public const string Beach = "07_BEACH";
	}
	public static class StorySegments
	{
		public const int INTRO_WAKEUP = 0;

		public const int INTRO_FINDWAYOUT = 1;

		public const int MOUNTAIN_WHEREAREYOU = 2;

		public const int MOUNTAIN_REPAIRBRIDGE = 3;

		public const int MOUNTAIN_BACKTOVILLAGE = 4;

		public const int MOUNTAIN_TALKTOPAINTER = 5;

		public const int MOUNTAIN_FINDPENCILHAT = 6;

		public const int MOUNTAIN_GIVEPENCILHATBACK = 7;

		public const int MOUNTAIN_DRAWSCARECROW = 8;

		public const int MOUNTAIN_PUTFACEONSCARECROW = 9;

		public const int MOUNTAIN_EXPLOREWORLD = 10;

		public const int MOUNTAIN_EXPLOREWORLD2 = 11;

		public const int FOREST_HELPVILLAGERSINTREE1 = 12;

		public const int FOREST_HELPVILLAGERSINTREE2_ROCK = 13;

		public const int FOREST_HELPVILLAGERSINTREE2 = 14;

		public const int FOREST_GOMEETPOINT = 15;

		public const int FOREST_GOTOCLUB = 16;

		public const int FOREST_GETSWAGGY = 17;

		public const int FOREST_ENTERCLUB = 18;

		public const int FOREST_CHALLENGEROBOT = 19;

		public const int FOREST_TALKTORESISTANCE = 20;

		public const int FOREST_FINDPURPOSECARD = 21;

		public const int FOREST_FOLLOWTHEREBELS = 22;

		public const int FOREST_BEATROBOT = 23;

		public const int FOREST_CELEBRATEVICTORY = 24;

		public const int FOREST_CELEBRATEVICTORY2 = 25;

		public const int MOUNTAIN_GETBACKMOUNTAIN = 26;

		public const int MOUNTAIN_BEATGIANTROBOT = 27;

		public const int FOREST_CELEBRATEVICTORYMOUNTAINBOSS = 28;

		public const int FOREST_FIXELECTRICITY = 29;

		public const int FOREST_GOTOTHELAKE = 30;

		public const int LAKE_INSPECT = 31;

		public const int LAKE_FINDKEY = 32;

		public const int LAKE_ENTERMINE = 33;

		public const int MINE_FOLLOWWORM = 34;

		public const int MINE_FOLLOWWORM2 = 35;

		public const int MINE_FINDERNIE = 36;

		public const int MINE_BRINGBACKERNIE = 37;

		public const int MINE_TALKTOREBELS = 38;

		public const int LAKE_FIGHTROBOT = 39;

		public const int HQ_OOPS = 40;

		public const int HQ_ARCHDPT1 = 41;

		public const int HQ_ARCHDPT2 = 42;

		public const int HQ_ESCAPE3 = 43;

		public const int HQ_ESCAPE_HELPVILLAGERS = 44;

		public const int HQ_BEATSUNSHINE1 = 45;

		public const int HQ_BEATSUNSHINE = 46;
	}
	public static class ArchipelagoConstants
	{
		public readonly struct CoinLoc
		{
			public readonly int Id;

			public readonly float X;

			public readonly float Y;

			public readonly string Name;

			public CoinLoc(int id, float x, float y, string name)
			{
				Id = id;
				X = x;
				Y = y;
				Name = name;
			}
		}

		public const string GameName = "Pikuniku";

		public const long BaseId = 100L;

		public static readonly Dictionary<string, long> Locations = new Dictionary<string, long>
		{
			{ "Walking Piku Trophy", 100L },
			{ "The Hidden Rock Trophy", 101L },
			{ "Baskick Champion Trophy", 102L },
			{ "Sam The Slime Trophy", 103L },
			{ "The Resistance Trophy", 104L },
			{ "A Giant Robot Trophy", 105L },
			{ "Demonic Toast Trophy", 106L },
			{ "PikDug Trophy", 107L },
			{ "Piku at The Beach Trophy", 108L },
			{ "The Worms Trophy", 109L },
			{ "Ernie the Worm Trophy", 110L },
			{ "Sunshine Inc. Robot Trophy", 111L },
			{ "Mr. Sunshine Trophy", 112L },
			{ "Valley Dancing Bug", 113L },
			{ "Road to Forest Dancing Bug", 114L },
			{ "Forest Dancing Bug", 115L },
			{ "Cave Dancing Bug", 116L },
			{ "Sunshine HQ Dancing Bug", 117L },
			{ "Valley Plush Purchase", 118L },
			{ "Forest Sunglasses Purchase", 119L },
			{ "Forest Postcard Purchase", 120L },
			{ "Forest X-Ray Goggles Purchase", 121L },
			{ "Pencil Hat", 122L },
			{ "Apple 1", 123L },
			{ "Apple 2", 124L },
			{ "Apple 3", 125L },
			{ "Beast Mask", 126L },
			{ "Flower Hat", 127L },
			{ "Draw on the Tree", 128L },
			{ "Magnetic Card", 129L },
			{ "Defeat the First Giant Robot", 130L },
			{ "Water Hat", 131L },
			{ "Golden Tooth from the Silver Frog", 132L },
			{ "Some Arms", 133L },
			{ "Defeat the Second Giant Robot", 134L },
			{ "The Cabin Key", 135L },
			{ "A Video Game", 136L },
			{ "A Detonator", 137L },
			{ "Defeat the Third Giant Robot", 138L },
			{ "Piku & Niku I Trophy", 139L },
			{ "Piku & Niku II Trophy", 140L },
			{ "Piku & Niku III Trophy", 141L },
			{ "Piku & Niku IV Trophy", 142L },
			{ "Piku & Niku V Trophy", 143L },
			{ "Co-op Level 1 Complete", 144L },
			{ "Co-op Level 2 Complete", 145L },
			{ "Co-op Level 3 Complete", 146L },
			{ "Co-op Level 4 Complete", 147L },
			{ "Co-op Level 5 Complete", 148L },
			{ "Co-op Level 6 Complete", 149L },
			{ "Co-op Level 7 Complete", 150L },
			{ "Co-op Level 8 Complete", 151L },
			{ "Co-op Level 9 Complete", 152L },
			{ "Valley: Coin near windmill 1", 153L },
			{ "Valley: Coin near windmill 2", 154L },
			{ "Valley: Coin near windmill 3", 155L },
			{ "Valley: Coin above shop", 156L },
			{ "Valley: Coin above umbrella", 157L },
			{ "Valley: Coin above cloud 1", 158L },
			{ "Valley: Coin above cloud 2", 159L },
			{ "Valley: Coin above cloud 3", 160L },
			{ "Valley: Coin above flower house", 161L },
			{ "Valley: Coin left under moving bridge", 162L },
			{ "Valley: Coin right under moving bridge", 163L },
			{ "Valley: Coin above lower cornfield 1", 164L },
			{ "Valley: Coin above lower cornfield 2", 165L },
			{ "Valley: Coin above lower cornfield 3", 166L },
			{ "Valley: Coin above lower cornfield 4", 167L },
			{ "Valley: Coin in air between cornfields 1", 168L },
			{ "Valley: Coin in air between cornfields 2", 169L },
			{ "Valley: Coin above upper cornfield 1", 170L },
			{ "Valley: Coin above upper cornfield 2", 171L },
			{ "Valley: Coin above upper cornfield 3", 172L },
			{ "Valley: Coin above upper cornfield 4", 173L },
			{ "Apple Temple: Coin next to spring", 174L },
			{ "Apple Temple: Coin on spike trap", 175L },
			{ "Apple Temple: Coin on first platform between spikes", 176L },
			{ "Apple Temple: Coin on second platform between spikes", 177L },
			{ "Apple Temple: Coin near hidden room", 178L },
			{ "Apple Temple: Coin after breakable rock 1", 179L },
			{ "Apple Temple: Coin after breakable rock 2", 180L },
			{ "Apple Temple: Coin after breakable rock 3", 181L },
			{ "Apple Temple: Coin requiring 2 buttons puzzle 1", 182L },
			{ "Apple Temple: Coin requiring 2 buttons puzzle 2", 183L },
			{ "Apple Temple: Coin requiring 2 buttons puzzle 3", 184L },
			{ "Apple Temple: Coin requiring 2 buttons puzzle 4", 185L },
			{ "Apple Temple: Coin requiring 2 buttons puzzle 5", 186L },
			{ "Apple Temple: Coin requiring 2 buttons puzzle 6", 187L },
			{ "Apple Temple: Coin between spike ceilings", 188L },
			{ "Apple Temple: Coin at start of bounce pad chain", 189L },
			{ "Apple Temple: Coin at end of temple 1", 190L },
			{ "Apple Temple: Coin at end of temple 2", 191L },
			{ "Apple Temple: Coin at end of temple 3", 192L },
			{ "Apple Temple: Coin at end of temple 4", 193L },
			{ "Valley Road: Coin at start", 194L },
			{ "Valley Road: Coin near hooks", 195L },
			{ "Valley Road: Coin on clouds above hooks", 196L },
			{ "Valley Road: Coin on clouds after boulders", 197L },
			{ "Valley Road: Coin in mushroom cave", 198L },
			{ "Valley Road: Coin on lower cave after door 1", 199L },
			{ "Valley Road: Coin on lower cave after door 2", 200L },
			{ "Valley Road: Coin on lower cave after door 3", 201L },
			{ "Valley Road: Coin on upper cloud near flower", 202L },
			{ "Valley Road: Coin on moving cloud 1", 203L },
			{ "Valley Road: Coin on moving cloud 2", 204L },
			{ "Valley Road: Coin on moving cloud 3", 205L },
			{ "Valley Road: Coin on moving cloud 4", 206L },
			{ "Valley Road: Coin on moving cloud 5", 207L },
			{ "Valley Road: Coin on moving cloud 6", 208L },
			{ "Valley Road: Coin on moving cloud 7", 209L },
			{ "Valley Road: Coin on moving cloud 8", 210L },
			{ "Valley Road: Coin on moving cloud 9", 211L },
			{ "Valley Road: Coin on moving cloud 10", 212L },
			{ "Valley Road: Coin on moving cloud 11", 213L },
			{ "Valley Road: Coin on moving cloud 12", 214L },
			{ "Valley Road: Coin on moving cloud 13", 215L },
			{ "Valley Road: Coin on moving cloud 14", 216L },
			{ "Valley Road: Coin at end of moving clouds", 217L },
			{ "Valley Road: Coin in hook upper hidden room 1", 218L },
			{ "Valley Road: Coin in hook upper hidden room 2", 219L },
			{ "Valley Road: Coin in hook upper hidden room 3", 220L },
			{ "Valley Road: Coin in hook upper hidden room 4", 221L },
			{ "Valley Road: Coin on zipline", 222L },
			{ "Valley Road: Coin on tree branch", 223L },
			{ "Valley Road: Coin near trees", 224L },
			{ "Valley Road: Coin in water hat area room 1", 225L },
			{ "Valley Road: Coin in water hat area room 2", 226L },
			{ "Valley Road: Coin in water hat area room 3", 227L },
			{ "Valley Road: Coin in water hat area room 4", 228L },
			{ "Forest: Coin on cut down log", 229L },
			{ "Forest: Coin on triple cut down logs 1", 230L },
			{ "Forest: Coin on triple cut down logs 2", 231L },
			{ "Forest: Coin on triple cut down logs 3", 232L },
			{ "Forest: Coin on ramp", 233L },
			{ "Forest: Coin on first log gear", 234L },
			{ "Forest: Coin on top of first log gear log", 235L },
			{ "Forest: Coin on second log gear", 236L },
			{ "Forest: Coin on fourth log", 237L },
			{ "Forest: Coin between logs", 238L },
			{ "Forest: Coin on fifth log gear", 239L },
			{ "Forest: Coin under sixth log gear", 240L },
			{ "Forest: Coin near owl on log", 241L },
			{ "Forest: Coin after logs", 242L },
			{ "Forest: Coin on town tree branch left", 243L },
			{ "Forest: Coin on town tree branch right", 244L },
			{ "Forest: Coin above community house", 245L },
			{ "Forest: Coin to the right of toastopia house", 246L },
			{ "Forest: Coin after rope bridge right of houses", 247L },
			{ "Forest: Coin atop last tree branch 1", 248L },
			{ "Forest: Coin atop last tree branch 2", 249L },
			{ "Forest: Coin on moving cloud 1", 250L },
			{ "Forest: Coin on moving cloud 2", 251L },
			{ "Forest: Coin on moving cloud 3", 252L },
			{ "Forest: Coin on moving cloud 4", 253L },
			{ "Forest: Coin on moving cloud 5", 254L },
			{ "Forest: Coin on moving cloud 6", 255L },
			{ "Forest: Coin on moving cloud 7", 256L },
			{ "Forest: Coin on moving cloud 8", 257L },
			{ "Forest: Coin on moving cloud 9", 258L },
			{ "Forest: Coin on moving cloud 10", 259L },
			{ "Forest: Coin on moving cloud 11", 260L },
			{ "Forest: Coin on moving cloud 12", 261L },
			{ "Forest: Coin on moving cloud 13", 262L },
			{ "Forest: Coin on moving cloud 14", 263L },
			{ "Forest: Coin on moving cloud 15", 264L },
			{ "Frog Temple: Coin left of entrance 1", 265L },
			{ "Frog Temple: Coin left of entrance 2", 266L },
			{ "Frog Temple: Coin left of entrance 3", 267L },
			{ "Frog Temple: Coin on spike trap", 268L },
			{ "Frog Temple: Coin before hook", 269L },
			{ "Frog Temple: Coin after 2nd checkpoint", 270L },
			{ "Frog Temple: Coin above arrow pit", 271L },
			{ "Frog Temple: Coin at symbol puzzle hint", 272L },
			{ "Frog Temple: Coin at nut bridge puzzle 1", 273L },
			{ "Frog Temple: Coin at nut bridge puzzle 2", 274L },
			{ "Frog Temple: Coin at nut bridge puzzle 3", 275L },
			{ "Cave: Coin in spring tunnel 1", 276L },
			{ "Cave: Coin in spring tunnel 2", 277L },
			{ "Cave: Coin in spring tunnel 3", 278L },
			{ "Cave: Coin in spring tunnel 4", 279L },
			{ "Cave: Coin after first pipe tunnel 1", 280L },
			{ "Cave: Coin after first pipe tunnel 2", 281L },
			{ "Cave: Coin before detonator tunnel 1", 282L },
			{ "Cave: Coin before detonator tunnel 2", 283L },
			{ "Cave: Coin before detonator tunnel 3", 284L },
			{ "Cave: Coin before detonator tunnel 4", 285L },
			{ "Cave: Coin near moving platforms", 286L },
			{ "Cave: Coin after first resistance puzzle 1", 287L },
			{ "Cave: Coin after first resistance puzzle 2", 288L },
			{ "Cave: Coin hidden near plant", 289L },
			{ "Cave: Coin after second resistance puzzle", 290L },
			{ "Cave: Coin above worm room 1", 291L },
			{ "Cave: Coin above worm room 2", 292L },
			{ "Cave: Coin under worm room", 293L },
			{ "Cave: Coin above ernie worm", 294L },
			{ "Cave: Coin above gray spinning cross 1", 295L },
			{ "Cave: Coin above gray spinning cross 2", 296L }
		};

		public static readonly Dictionary<string, long> Items = new Dictionary<string, long>
		{
			{ "Pencil Hat", 100L },
			{ "Water Hat", 101L },
			{ "Sunglasses", 102L },
			{ "X-Ray Glasses", 103L },
			{ "Flower Hat", 104L },
			{ "Beast Mask", 105L },
			{ "Some Arms", 106L },
			{ "Magnetic Card", 107L },
			{ "The Cabin Key", 108L },
			{ "A Detonator", 109L },
			{ "Apple", 110L },
			{ "The Golden Tooth from the Silver Frog", 111L },
			{ "Co-op Level Access", 112L },
			{ "A Video Game", 113L },
			{ "Sam the Slime Trophy", 114L },
			{ "The Resistance Trophy", 115L },
			{ "A Giant Robot Trophy", 116L },
			{ "The Demonic Toast Trophy", 117L },
			{ "PikDug Trophy", 118L },
			{ "Piku at the Beach Trophy", 119L },
			{ "The Worms Trophy", 120L },
			{ "Ernie the Worm Trophy", 121L },
			{ "Sunshine Inc. Robot Trophy", 122L },
			{ "Mr. Sunshine Trophy", 123L },
			{ "Baskick Champion Trophy", 124L },
			{ "Walking Piku Trophy", 125L },
			{ "The Hidden Rock Trophy", 126L },
			{ "Piku & Niku I Trophy", 127L },
			{ "Piku & Niku II Trophy", 128L },
			{ "Piku & Niku III Trophy", 129L },
			{ "Piku & Niku IV Trophy", 130L },
			{ "Piku & Niku V Trophy", 131L },
			{ "A Scary Plush", 132L },
			{ "Forest Postcard", 133L },
			{ "5 Coins", 134L },
			{ "Joyful Whimsy", 135L }
		};

		public static readonly CoinLoc[] CoinLocations = new CoinLoc[144]
		{
			new CoinLoc(1199576228, 290.5f, -81.1f, "Valley: Coin near windmill 1"),
			new CoinLoc(889188242, 293.2f, -81.1f, "Valley: Coin near windmill 2"),
			new CoinLoc(889144834, 295.7f, -81f, "Valley: Coin near windmill 3"),
			new CoinLoc(889149006, 364.8f, -57.6f, "Valley: Coin above shop"),
			new CoinLoc(889178494, 377.8f, -60.2f, "Valley: Coin above umbrella"),
			new CoinLoc(889169866, 413.2f, -26.6f, "Valley: Coin above cloud 1"),
			new CoinLoc(889134516, 415.8f, -26.6f, "Valley: Coin above cloud 2"),
			new CoinLoc(889122018, 418.4f, -26.6f, "Valley: Coin above cloud 3"),
			new CoinLoc(889153857, 432f, -50.7f, "Valley: Coin above flower house"),
			new CoinLoc(889161219, 453f, -97f, "Valley: Coin left under moving bridge"),
			new CoinLoc(889106873, 469f, -103f, "Valley: Coin right under moving bridge"),
			new CoinLoc(889191034, 175f, -89f, "Valley: Coin above lower cornfield 1"),
			new CoinLoc(889123450, 177f, -89f, "Valley: Coin above lower cornfield 2"),
			new CoinLoc(889121971, 179f, -89f, "Valley: Coin above lower cornfield 3"),
			new CoinLoc(1199575527, 181f, -89f, "Valley: Coin above lower cornfield 4"),
			new CoinLoc(889188847, 158.4f, -77.8f, "Valley: Coin in air between cornfields 1"),
			new CoinLoc(889156023, 158.4f, -80.8f, "Valley: Coin in air between cornfields 2"),
			new CoinLoc(889186242, 172f, -74f, "Valley: Coin above upper cornfield 1"),
			new CoinLoc(889184443, 173.9f, -73.9f, "Valley: Coin above upper cornfield 2"),
			new CoinLoc(889118349, 175.9f, -73.9f, "Valley: Coin above upper cornfield 3"),
			new CoinLoc(889135973, 178f, -74f, "Valley: Coin above upper cornfield 4"),
			new CoinLoc(51908967, 11.4f, 7.1f, "Apple Temple: Coin next to spring"),
			new CoinLoc(51846333, 15f, -17f, "Apple Temple: Coin on spike trap"),
			new CoinLoc(51821243, 33f, -21f, "Apple Temple: Coin on first platform between spikes"),
			new CoinLoc(895346862, 44f, -21f, "Apple Temple: Coin on second platform between spikes"),
			new CoinLoc(51833320, 82f, -5f, "Apple Temple: Coin near hidden room"),
			new CoinLoc(51883161, 109.6f, -17.4f, "Apple Temple: Coin after breakable rock 1"),
			new CoinLoc(51834740, 111.6f, -17.4f, "Apple Temple: Coin after breakable rock 2"),
			new CoinLoc(51853567, 113.6f, -17.4f, "Apple Temple: Coin after breakable rock 3"),
			new CoinLoc(51825124, 163.2f, -40.8f, "Apple Temple: Coin requiring 2 buttons puzzle 1"),
			new CoinLoc(51828777, 165.2f, -40.8f, "Apple Temple: Coin requiring 2 buttons puzzle 2"),
			new CoinLoc(51834651, 167.2f, -40.8f, "Apple Temple: Coin requiring 2 buttons puzzle 3"),
			new CoinLoc(51847808, 163.2f, -43.1f, "Apple Temple: Coin requiring 2 buttons puzzle 4"),
			new CoinLoc(51829431, 165.2f, -43.1f, "Apple Temple: Coin requiring 2 buttons puzzle 5"),
			new CoinLoc(51893689, 167.2f, -43.1f, "Apple Temple: Coin requiring 2 buttons puzzle 6"),
			new CoinLoc(1723174925, 215f, -46.9f, "Apple Temple: Coin between spike ceilings"),
			new CoinLoc(51854706, 226.1f, -35.8f, "Apple Temple: Coin at start of bounce pad chain"),
			new CoinLoc(51885771, 271.6f, -22.7f, "Apple Temple: Coin at end of temple 1"),
			new CoinLoc(51838646, 268.6f, -25.5f, "Apple Temple: Coin at end of temple 2"),
			new CoinLoc(51878197, 268.6f, -22.7f, "Apple Temple: Coin at end of temple 3"),
			new CoinLoc(1723174131, 265.6f, -22.7f, "Apple Temple: Coin at end of temple 4"),
			new CoinLoc(70776915, 22.8f, -76f, "Valley Road: Coin at start"),
			new CoinLoc(70776915, 85f, -63f, "Valley Road: Coin near hooks"),
			new CoinLoc(70776915, 69f, -37.7f, "Valley Road: Coin on clouds above hooks"),
			new CoinLoc(70776915, 147.6f, -53.8f, "Valley Road: Coin on clouds after boulders"),
			new CoinLoc(70776915, 209f, -63f, "Valley Road: Coin in mushroom cave"),
			new CoinLoc(70776915, 246.1f, -82.9f, "Valley Road: Coin on lower cave after door 1"),
			new CoinLoc(70776915, 253.5f, -82.9f, "Valley Road: Coin on lower cave after door 2"),
			new CoinLoc(70776915, 260.9f, -82.9f, "Valley Road: Coin on lower cave after door 3"),
			new CoinLoc(70776915, 216.5f, -17.2f, "Valley Road: Coin on upper cloud near flower"),
			new CoinLoc(70776915, 190f, 1.4f, "Valley Road: Coin on moving cloud 1"),
			new CoinLoc(70776915, 191.8f, 1.4f, "Valley Road: Coin on moving cloud 2"),
			new CoinLoc(70776915, 193.5f, 1.4f, "Valley Road: Coin on moving cloud 3"),
			new CoinLoc(70776915, 195.6f, 1.4f, "Valley Road: Coin on moving cloud 4"),
			new CoinLoc(70776915, 190f, -0.6f, "Valley Road: Coin on moving cloud 5"),
			new CoinLoc(70776915, 191.8f, -0.6f, "Valley Road: Coin on moving cloud 6"),
			new CoinLoc(70776915, 193.5f, -0.6f, "Valley Road: Coin on moving cloud 7"),
			new CoinLoc(70776915, 195.6f, -0.6f, "Valley Road: Coin on moving cloud 8"),
			new CoinLoc(70776915, 204.4f, 1.4f, "Valley Road: Coin on moving cloud 9"),
			new CoinLoc(70776915, 206.2f, 1.4f, "Valley Road: Coin on moving cloud 10"),
			new CoinLoc(70776915, 207.9f, 1.4f, "Valley Road: Coin on moving cloud 11"),
			new CoinLoc(70776915, 204.4f, -0.6f, "Valley Road: Coin on moving cloud 12"),
			new CoinLoc(70776915, 206.2f, -0.6f, "Valley Road: Coin on moving cloud 13"),
			new CoinLoc(70776915, 207.9f, -0.6f, "Valley Road: Coin on moving cloud 14"),
			new CoinLoc(70776915, 140.9f, -5f, "Valley Road: Coin at end of moving clouds"),
			new CoinLoc(70776915, 125.2f, -15.5f, "Valley Road: Coin in hook upper hidden room 1"),
			new CoinLoc(70776915, 127f, -15.5f, "Valley Road: Coin in hook upper hidden room 2"),
			new CoinLoc(70776915, 125.2f, -13.5f, "Valley Road: Coin in hook upper hidden room 3"),
			new CoinLoc(70776915, 127f, -13.5f, "Valley Road: Coin in hook upper hidden room 4"),
			new CoinLoc(70776915, 305.3f, -16.2f, "Valley Road: Coin on zipline"),
			new CoinLoc(70776915, 320.4f, -29.1f, "Valley Road: Coin on tree branch"),
			new CoinLoc(62192953, 334.8f, -41.2f, "Valley Road: Coin near trees"),
			new CoinLoc(2085386414, 144f, -98f, "Valley Road: Coin in water hat area room 1"),
			new CoinLoc(2092971986, 138f, -98f, "Valley Road: Coin in water hat area room 2"),
			new CoinLoc(649749052, 133f, -98f, "Valley Road: Coin in water hat area room 3"),
			new CoinLoc(2093405322, 128.6f, -98f, "Valley Road: Coin in water hat area room 4"),
			new CoinLoc(1549184843, 55f, -195f, "Forest: Coin on cut down log"),
			new CoinLoc(1549224845, 141f, -206f, "Forest: Coin on triple cut down logs 1"),
			new CoinLoc(1549205227, 149f, -206f, "Forest: Coin on triple cut down logs 2"),
			new CoinLoc(1549228498, 157f, -204f, "Forest: Coin on triple cut down logs 3"),
			new CoinLoc(1549214684, 189.8f, -209.3f, "Forest: Coin on ramp"),
			new CoinLoc(1667825996, 219.2f, -194.6f, "Forest: Coin on first log gear"),
			new CoinLoc(1549200294, 219.1f, -189f, "Forest: Coin on top of first log gear log"),
			new CoinLoc(1549220811, 245f, -187f, "Forest: Coin on second log gear"),
			new CoinLoc(1549151259, 277f, -163f, "Forest: Coin on fourth log"),
			new CoinLoc(1702486725, 298f, -164.8f, "Forest: Coin between logs"),
			new CoinLoc(1703946260, 327f, -158.7f, "Forest: Coin on fifth log gear"),
			new CoinLoc(1549188468, 339.1f, -185.6f, "Forest: Coin under sixth log gear"),
			new CoinLoc(1548603409, 363f, -137f, "Forest: Coin near owl on log"),
			new CoinLoc(1549154939, 374f, -146f, "Forest: Coin after logs"),
			new CoinLoc(1839019233, 488.9f, -163.9f, "Forest: Coin on town tree branch left"),
			new CoinLoc(1839992568, 497.3f, -155.4f, "Forest: Coin on town tree branch right"),
			new CoinLoc(1834202660, 529.1f, -152.1f, "Forest: Coin above community house"),
			new CoinLoc(1837535892, 605.1f, -156f, "Forest: Coin to the right of toastopia house"),
			new CoinLoc(154918642, 653f, -169f, "Forest: Coin after rope bridge right of houses"),
			new CoinLoc(1549206017, 658f, -153f, "Forest: Coin atop last tree branch 1"),
			new CoinLoc(1549213430, 658f, -144.6f, "Forest: Coin atop last tree branch 2"),
			new CoinLoc(1549218646, 626.1f, -105.7f, "Forest: Coin on moving cloud 1"),
			new CoinLoc(1549221410, 629.1f, -105.7f, "Forest: Coin on moving cloud 2"),
			new CoinLoc(1549196638, 632.1f, -105.7f, "Forest: Coin on moving cloud 3"),
			new CoinLoc(1549176235, 635.1f, -105.7f, "Forest: Coin on moving cloud 4"),
			new CoinLoc(1549150881, 638.1f, -105.7f, "Forest: Coin on moving cloud 5"),
			new CoinLoc(1549213502, 629.1f, -108f, "Forest: Coin on moving cloud 6"),
			new CoinLoc(1549208573, 632.1f, -108f, "Forest: Coin on moving cloud 7"),
			new CoinLoc(1549200835, 635.1f, -108f, "Forest: Coin on moving cloud 8"),
			new CoinLoc(1549186031, 638.1f, -108f, "Forest: Coin on moving cloud 9"),
			new CoinLoc(1549163596, 649.1f, -105.7f, "Forest: Coin on moving cloud 10"),
			new CoinLoc(1549170179, 652.1f, -105.7f, "Forest: Coin on moving cloud 11"),
			new CoinLoc(1549163589, 655.1f, -105.7f, "Forest: Coin on moving cloud 12"),
			new CoinLoc(1549185406, 649.1f, -108f, "Forest: Coin on moving cloud 13"),
			new CoinLoc(1549232206, 652.1f, -108f, "Forest: Coin on moving cloud 14"),
			new CoinLoc(1549211934, 655.1f, -108f, "Forest: Coin on moving cloud 15"),
			new CoinLoc(740310583, 8f, 10f, "Frog Temple: Coin left of entrance 1"),
			new CoinLoc(740050088, 11f, 10f, "Frog Temple: Coin left of entrance 2"),
			new CoinLoc(739750294, 14f, 10f, "Frog Temple: Coin left of entrance 3"),
			new CoinLoc(1099654487, 70.1f, 9.6f, "Frog Temple: Coin on spike trap"),
			new CoinLoc(1096215408, 97.8f, 5.6f, "Frog Temple: Coin before hook"),
			new CoinLoc(1096215408, 130.1f, 8.6f, "Frog Temple: Coin after 2nd checkpoint"),
			new CoinLoc(522213601, 236.2f, -9.7f, "Frog Temple: Coin above arrow pit"),
			new CoinLoc(525698043, 304f, -14f, "Frog Temple: Coin at symbol puzzle hint"),
			new CoinLoc(1706505722, 354.2f, -17.1f, "Frog Temple: Coin at nut bridge puzzle 1"),
			new CoinLoc(1706215749, 356.7f, -17.1f, "Frog Temple: Coin at nut bridge puzzle 2"),
			new CoinLoc(1706088097, 359.3f, -17.1f, "Frog Temple: Coin at nut bridge puzzle 3"),
			new CoinLoc(73042658, 202f, -20f, "Cave: Coin in spring tunnel 1"),
			new CoinLoc(1182784534, 205.6f, -20f, "Cave: Coin in spring tunnel 2"),
			new CoinLoc(1182624852, 209.1f, -20f, "Cave: Coin in spring tunnel 3"),
			new CoinLoc(1182375973, 212.6f, -20f, "Cave: Coin in spring tunnel 4"),
			new CoinLoc(1248839813, 153.6f, -157.3f, "Cave: Coin after first pipe tunnel 1"),
			new CoinLoc(1248221666, 153.6f, -160f, "Cave: Coin after first pipe tunnel 2"),
			new CoinLoc(1249179375, 142.7f, -157.3f, "Cave: Coin before detonator tunnel 1"),
			new CoinLoc(1249379767, 145.5f, -157.3f, "Cave: Coin before detonator tunnel 2"),
			new CoinLoc(1248403122, 142.7f, -160f, "Cave: Coin before detonator tunnel 3"),
			new CoinLoc(1248666468, 145.5f, -160f, "Cave: Coin before detonator tunnel 4"),
			new CoinLoc(110171987, 218f, -146f, "Cave: Coin near moving platforms"),
			new CoinLoc(110514548, 242f, -179f, "Cave: Coin after first resistance puzzle 1"),
			new CoinLoc(109996565, 245f, -179f, "Cave: Coin after first resistance puzzle 2"),
			new CoinLoc(119674886, 268f, -163f, "Cave: Coin hidden near plant"),
			new CoinLoc(119361553, 380.5f, -173.2f, "Cave: Coin after second resistance puzzle"),
			new CoinLoc(120455579, 444.9f, -167f, "Cave: Coin above worm room 1"),
			new CoinLoc(120475059, 457.4f, -167f, "Cave: Coin above worm room 2"),
			new CoinLoc(179300603, 471.2f, -204.8f, "Cave: Coin under worm room"),
			new CoinLoc(180586320, 497f, -221f, "Cave: Coin above ernie worm"),
			new CoinLoc(182877868, 552.7f, -198.4f, "Cave: Coin above gray spinning cross 1"),
			new CoinLoc(448907562, 559.8f, -202.4f, "Cave: Coin above gray spinning cross 2")
		};

		public static string ResolveCoinLocation(int uniqueId, float x, float y)
		{
			string result = null;
			float num = float.MaxValue;
			CoinLoc[] coinLocations = CoinLocations;
			for (int i = 0; i < coinLocations.Length; i++)
			{
				CoinLoc coinLoc = coinLocations[i];
				if (coinLoc.Id == uniqueId)
				{
					float num2 = coinLoc.X - x;
					float num3 = coinLoc.Y - y;
					float num4 = num2 * num2 + num3 * num3;
					if (num4 < num)
					{
						num = num4;
						result = coinLoc.Name;
					}
				}
			}
			return result;
		}
	}
	public class ArchipelagoHandler : MonoBehaviour
	{
		private string seed;

		private readonly Queue<long> locationsToCheck = new Queue<long>();

		private readonly object queueLock = new object();

		private string lastDeath;

		private DateTime lastDeathLinkTime = DateTime.Now;

		private readonly Random random = new Random();

		private readonly string[] deathMessages = new string[6] { "got kicked a little too hard.", "should not have trusted Mr. Sunshine.", "drank too much green liquid.", "got FREE MONEY!!!", "got chosen to go to the volcano.", "got kicked out of el bunko." };

		private int _gameOversSinceLastSend;

		private ArchipelagoSession Session { get; set; }

		private string Server { get; set; }

		private int Port { get; set; }

		private string Slot { get; set; }

		private string Password { get; set; }

		public bool IsConnected
		{
			get
			{
				if (Session != null)
				{
					return Session.Socket.Connected;
				}
				return false;
			}
		}

		public bool DeathLinkEnabled => PikunikuAPMod.DeathLink?.Value switch
		{
			DeathLinkMode.On => true, 
			DeathLinkMode.Off => false, 
			_ => PikunikuAPMod.SlotData?.DeathLink ?? false, 
		};

		public event Action OnConnected;

		public event Action<string> OnConnectionFailed;

		public event Action OnDisconnected;

		public event Action<string> OnLogMessage;

		private static string GetColorHex(PaletteColor? color)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected I4, but got Unknown
			return color switch
			{
				(PaletteColor)2L => "#EE0000", 
				(PaletteColor)3L => "#00FF7F", 
				(PaletteColor)7L => "#FAFAD2", 
				(PaletteColor)4L => "#6495ED", 
				(PaletteColor)6L => "#EE00EE", 
				(PaletteColor)5L => "#00EEEE", 
				(PaletteColor)1L => "#000000", 
				(PaletteColor)0L => "#FFFFFF", 
				(PaletteColor)8L => "#6D8BE8", 
				(PaletteColor)9L => "#FA8072", 
				(PaletteColor)10L => "#AF99EF", 
				_ => "#FFFFFF", 
			};
		}

		public void CreateSession(string server, int port, string slot, string password)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			Server = server;
			Port = port;
			Slot = slot;
			Password = password;
			Session = ArchipelagoSessionFactory.CreateSession(Server, Port);
			Session.MessageLog.OnMessageReceived += new MessageReceivedHandler(OnMessageReceived);
			Session.Socket.ErrorReceived += new ErrorReceivedHandler(OnError);
			Session.Socket.SocketClosed += new SocketClosedHandler(OnSocketClosed);
			Session.Socket.PacketReceived += new PacketReceivedHandler(PacketReceived);
			Session.Items.ItemReceived += new ItemReceivedHandler(ItemReceived);
		}

		private void OnDestroy()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			if (Session != null)
			{
				Session.MessageLog.OnMessageReceived -= new MessageReceivedHandler(OnMessageReceived);
				Session.Socket.ErrorReceived -= new ErrorReceivedHandler(OnError);
				Session.Socket.SocketClosed -= new SocketClosedHandler(OnSocketClosed);
				Session.Socket.PacketReceived -= new PacketReceivedHandler(PacketReceived);
				Session.Items.ItemReceived -= new ItemReceivedHandler(ItemReceived);
			}
		}

		public void Connect()
		{
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			Log.Message($"Logging in to {Server}:{Port} as {Slot}...");
			LoginResult val = Session.TryConnectAndLogin("Pikuniku", Slot, (ItemsHandlingFlags)7, new Version(0, 6, 7), new string[0], (string)null, Password, true);
			if (val.Successful)
			{
				Log.Message($"Success! Connected to {Server}:{Port}");
				LoginSuccessful val2 = (LoginSuccessful)val;
				PikunikuAPMod.SlotData = new SlotData(val2.SlotData);
				Log.Info(val2.SlotData);
				Log.Info(PikunikuAPMod.SlotData.PikuColor);
				Log.Info(PikunikuAPMod.SlotData.DeathLinkAmnesty);
				Log.Info(PikunikuAPMod.SlotData.DeathLink);
				Log.Info(PikunikuAPMod.SlotData.Coinsanity);
				Log.Info(PikunikuAPMod.SlotData.CoopLevels);
				ApplyDeathLinkTag();
				seed = Session.RoomState.Seed;
				if (seed != null)
				{
					PikunikuAPMod.SaveDataHandler.GetSaveGame(seed, Slot);
					PikunikuAPMod.GameHandler.SetupSeedSlot(seed, Slot);
				}
				PikunikuAPMod.GameHandler.InitOnConnect();
				((MonoBehaviour)this).StartCoroutine(RunCheckQueue());
				this.OnConnected?.Invoke();
			}
			else
			{
				LoginFailure val3 = (LoginFailure)val;
				string text = Enumerable.Aggregate(seed: Enumerable.Aggregate(seed: $"Failed to Connect to {Server}:{Port} as {Slot}:", source: val3.Errors, func: (string current, string error) => current + "\n    " + error), source: val3.ErrorCodes, func: (string current, ConnectionRefusedError error) => current + $"\n    {error}");
				this.OnConnectionFailed?.Invoke(text);
				Log.Error(text);
			}
		}

		public void Disconnect()
		{
			if (Session != null)
			{
				((MonoBehaviour)this).StopAllCoroutines();
				Session.Socket.Disconnect();
				Session = null;
				Log.Message("Disconnected from Archipelago");
			}
		}

		private void OnError(Exception ex, string message)
		{
			Log.Error("Socket error: " + message + " - " + ex.Message);
		}

		private void OnSocketClosed(string reason)
		{
			((MonoBehaviour)this).StopAllCoroutines();
			Log.Warning("Socket closed: " + reason);
			this.OnDisconnected?.Invoke();
		}

		private void ItemReceived(ReceivedItemsHelper helper)
		{
			try
			{
				int valueOrDefault = (PikunikuAPMod.SaveDataHandler?.SaveData?.ItemIndex).GetValueOrDefault();
				while (helper.Any())
				{
					ItemInfo item = helper.DequeueItem();
					int num = helper.Index - 1;
					if (num >= valueOrDefault)
					{
						PikunikuAPMod.ItemHandler.HandleItem(num, item);
					}
				}
			}
			catch (Exception arg)
			{
				Log.Error($"ItemReceived Error: {arg}");
				throw;
			}
		}

		public void SetGoal()
		{
			Session.SetGoalAchieved();
			Session.SetClientState((ArchipelagoClientState)30);
		}

		public void CheckLocations(long[] ids)
		{
			lock (queueLock)
			{
				foreach (long item in ids)
				{
					locationsToCheck.Enqueue(item);
				}
			}
		}

		public void CheckLocation(long id)
		{
			if (IsLocationChecked(id))
			{
				return;
			}
			lock (queueLock)
			{
				locationsToCheck.Enqueue(id);
			}
		}

		private IEnumerator RunCheckQueue()
		{
			while (true)
			{
				long num = 0L;
				bool flag = false;
				lock (queueLock)
				{
					if (locationsToCheck.Count > 0)
					{
						num = locationsToCheck.Dequeue();
						flag = true;
					}
				}
				if (flag)
				{
					Session.Locations.CompleteLocationChecks(new long[1] { num });
					Log.Message($"Sent location check: {num}");
				}
				yield return (object)new WaitForSeconds(0.1f);
			}
		}

		public bool HasReceivedItem(string itemName)
		{
			if (Session == null || Session.Items == null)
			{
				return false;
			}
			return Session.Items.AllItemsReceived.Any((ItemInfo item) => item.ItemName == itemName);
		}

		public bool IsLocationChecked(long id)
		{
			if (Session == null || Session.Locations == null)
			{
				return false;
			}
			return Session.Locations.AllLocationsChecked.Contains(id);
		}

		public int CountLocationsCheckedInRange(long start, long end)
		{
			if (Session == null || Session.Locations == null)
			{
				return 0;
			}
			return Session.Locations.AllLocationsChecked.Count((long loc) => loc >= start && loc < end);
		}

		public void UpdateTags(List<string> tags)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if (Session != null)
			{
				ConnectUpdatePacket val = new ConnectUpdatePacket
				{
					Tags = tags.ToArray(),
					ItemsHandling = (ItemsHandlingFlags)7
				};
				Session.Socket.SendPacket((ArchipelagoPacketBase)(object)val);
			}
		}

		public void ApplyDeathLinkTag()
		{
			UpdateTags(DeathLinkEnabled ? new List<string> { "DeathLink" } : new List<string>());
		}

		private void OnMessageReceived(LogMessage message)
		{
			if (message.Parts.Any((MessagePart x) => (int)x.Type == 1) && PikunikuAPMod.FilterLog != null && PikunikuAPMod.FilterLog.Value && !message.Parts.Any((MessagePart x) => x.Text.Contains(Session.Players.GetPlayerName(Session.ConnectionInfo.Slot))))
			{
				return;
			}
			string message2;
			if (message.Parts.Length == 1)
			{
				message2 = message.Parts[0].Text;
			}
			else
			{
				StringBuilder stringBuilder = new StringBuilder();
				MessagePart[] parts = message.Parts;
				foreach (MessagePart val in parts)
				{
					string colorHex = GetColorHex(val.PaletteColor);
					stringBuilder.Append("<color=" + colorHex + ">" + val.Text + "</color>");
				}
				message2 = stringBuilder.ToString();
			}
			AddMessageToGameLog(message2);
		}

		public void AddMessageToGameLog(string message)
		{
			Log.Message(message);
			this.OnLogMessage?.Invoke(message);
		}

		private void PacketReceived(ArchipelagoPacketBase packet)
		{
			BouncePacket val = (BouncePacket)(object)((packet is BouncePacket) ? packet : null);
			if (val != null)
			{
				BouncePacketReceived(val);
			}
		}

		public void OnPlayerGameOver()
		{
			if (DeathLinkEnabled)
			{
				int num = PikunikuAPMod.SlotData?.DeathLinkAmnesty ?? 0;
				_gameOversSinceLastSend++;
				if (_gameOversSinceLastSend <= num)
				{
					Log.Message($"DeathLink amnesty {_gameOversSinceLastSend}/{num} — not sending");
					return;
				}
				_gameOversSinceLastSend = 0;
				SendDeath();
			}
		}

		public void SendDeath()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			if (DeathLinkEnabled)
			{
				BouncePacket val = new BouncePacket();
				DateTime now = DateTime.Now;
				if (!(now - lastDeathLinkTime < TimeSpan.FromSeconds(2.0)))
				{
					val.Tags = new List<string>(1) { "DeathLink" };
					val.Data = new Dictionary<string, JToken>
					{
						{
							"time",
							JToken.op_Implicit(UnixTimeConverter.ToUnixTimeStamp(now))
						},
						{
							"source",
							JToken.op_Implicit(Slot)
						},
						{
							"cause",
							JToken.op_Implicit(Slot + " " + deathMessages[random.Next(deathMessages.Length)])
						}
					};
					lastDeathLinkTime = now;
					Session.Socket.SendPacket((ArchipelagoPacketBase)(object)val);
				}
			}
		}

		private void BouncePacketReceived(BouncePacket packet)
		{
			if (DeathLinkEnabled)
			{
				ProcessBouncePacket(packet, "DeathLink", ref lastDeath, delegate(string source, Dictionary<string, JToken> data)
				{
					JToken value;
					string cause = (data.TryGetValue("cause", out value) ? ((object)value).ToString() : (source + " has died."));
					HandleDeathLink(source, cause);
				});
			}
		}

		private static void ProcessBouncePacket(BouncePacket packet, string tag, ref string lastTime, Action<string, Dictionary<string, JToken>> handler)
		{
			if (packet.Tags.Contains(tag) && packet.Data.TryGetValue("time", out var value) && !(lastTime == ((object)value).ToString()))
			{
				lastTime = ((object)value).ToString();
				if (packet.Data.TryGetValue("source", out var value2))
				{
					string arg = ((object)value2)?.ToString() ?? "Unknown";
					handler(arg, packet.Data);
				}
			}
		}

		private void HandleDeathLink(string source, string cause)
		{
			AddMessageToGameLog(cause);
			if (!(source == Slot))
			{
				PikunikuAPMod.GameHandler.Kill();
			}
		}

		public void ScoutLocation(long locationId, Action<ScoutedItemInfo> callback, bool createHint = false)
		{
			Session.Locations.ScoutLocationsAsync((Action<Dictionary<long, ScoutedItemInfo>>)delegate(Dictionary<long, ScoutedItemInfo> results)
			{
				if (results != null && results.Count > 0)
				{
					callback?.Invoke(results.Values.First());
				}
			}, createHint, new long[1] { locationId });
		}

		public string GetPlayerName(int player)
		{
			return Session.Players.GetPlayerAlias(player) ?? $"Player {player}";
		}

		public string GetLocationName(long locationId)
		{
			return Session.Locations.GetLocationNameFromId(locationId, (string)null) ?? $"Location {locationId}";
		}
	}
	public class ClientView : MonoBehaviour
	{
		private class Message
		{
			public GameObject Go;

			public CanvasGroup Cg;

			public float Born;

			public float Expiry;
		}

		private const float MessageLifetime = 7.5f;

		private const float FadeIn = 0.25f;

		private const float FadeOut = 0.6f;

		private const float PanelWidth = 440f;

		private const float PanelHeight = 300f;

		private const float FontSize = 18f;

		private static readonly Color ShadowColor = new Color(0f, 0f, 0f, 0.9f);

		private static readonly Vector2 ShadowDistance = new Vector2(1f, -1f);

		private Canvas _canvas;

		private RectTransform _content;

		private TMP_FontAsset _font;

		private bool _built;

		private volatile bool _wantVisible;

		private float _systemMessageUntil;

		private readonly List<Message> _messages = new List<Message>();

		private readonly Queue<string> _incoming = new Queue<string>();

		private readonly object _lock = new object();

		private void Awake()
		{
			ArchipelagoHandler archipelagoHandler = PikunikuAPMod.ArchipelagoHandler;
			if ((Object)(object)archipelagoHandler != (Object)null)
			{
				archipelagoHandler.OnLogMessage += OnLogMessage;
				archipelagoHandler.OnConnected += OnConnected;
				archipelagoHandler.OnDisconnected += OnDisconnected;
			}
		}

		private void OnDestroy()
		{
			ArchipelagoHandler archipelagoHandler = PikunikuAPMod.ArchipelagoHandler;
			if ((Object)(object)archipelagoHandler != (Object)null)
			{
				archipelagoHandler.OnLogMessage -= OnLogMessage;
				archipelagoHandler.OnConnected -= OnConnected;
				archipelagoHandler.OnDisconnected -= OnDisconnected;
			}
		}

		private void OnLogMessage(string message)
		{
			lock (_lock)
			{
				_incoming.Enqueue(message);
			}
		}

		private void OnConnected()
		{
			_wantVisible = true;
		}

		private void OnDisconnected()
		{
			_wantVisible = false;
		}

		public void QueueMessage(string text)
		{
			lock (_lock)
			{
				_incoming.Enqueue(text);
			}
			_systemMessageUntil = Mathf.Max(_systemMessageUntil, Time.unscaledTime + 7.5f);
		}

		private void Update()
		{
			float unscaledTime = Time.unscaledTime;
			bool flag = _wantVisible || unscaledTime < _systemMessageUntil;
			if (flag && !_built)
			{
				Build();
			}
			if (!_built)
			{
				return;
			}
			if (((Behaviour)_canvas).enabled != flag)
			{
				((Behaviour)_canvas).enabled = flag;
			}
			lock (_lock)
			{
				while (_incoming.Count > 0)
				{
					AddMessage(_incoming.Dequeue(), unscaledTime);
				}
			}
			for (int num = _messages.Count - 1; num >= 0; num--)
			{
				Message message = _messages[num];
				if (unscaledTime >= message.Expiry)
				{
					if ((Object)(object)message.Go != (Object)null)
					{
						Object.Destroy((Object)(object)message.Go);
					}
					_messages.RemoveAt(num);
				}
				else if ((Object)(object)message.Cg != (Object)null)
				{
					message.Cg.alpha = ComputeAlpha(message, unscaledTime);
				}
			}
		}

		private static float ComputeAlpha(Message m, float now)
		{
			float num = 1f;
			float num2 = now - m.Born;
			if (num2 < 0.25f)
			{
				num = num2 / 0.25f;
			}
			float num3 = m.Expiry - now;
			if (num3 < 0.6f)
			{
				num = Mathf.Min(num, num3 / 0.6f);
			}
			return Mathf.Clamp01(num);
		}

		private void AddMessage(string text, float now)
		{
			//IL_0019: 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_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = MakeRect("Msg", (Transform)(object)_content);
			TextMeshProUGUI obj = ConfigureText(val);
			((Graphic)obj).color = ShadowColor;
			((TMP_Text)obj).text = StripColorTags(text);
			GameObject val2 = MakeRect("Text", val.transform);
			TextMeshProUGUI obj2 = ConfigureText(val2);
			((Graphic)obj2).color = Color.white;
			((TMP_Text)obj2).text = text;
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor(0f - ShadowDistance.x, 0f - ShadowDistance.y);
			val3.offsetMax = val4;
			val3.offsetMin = val4;
			CanvasGroup val5 = val.AddComponent<CanvasGroup>();
			val5.alpha = 0f;
			val5.interactable = false;
			val5.blocksRaycasts = false;
			_messages.Add(new Message
			{
				Go = val,
				Cg = val5,
				Born = now,
				Expiry = now + 7.5f
			});
		}

		private TextMeshProUGUI ConfigureText(GameObject go)
		{
			TextMeshProUGUI val = go.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val).fontSize = 18f;
			((TMP_Text)val).richText = true;
			((TMP_Text)val).enableWordWrapping = true;
			((TMP_Text)val).alignment = (TextAlignmentOptions)1025;
			((Graphic)val).raycastTarget = false;
			if ((Object)(object)_font != (Object)null)
			{
				((TMP_Text)val).font = _font;
			}
			return val;
		}

		private static string StripColorTags(string text)
		{
			return Regex.Replace(text, "</?color[^>]*>", string.Empty);
		}

		private void Build()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			_font = FindGameFont();
			GameObject val = new GameObject("AP_ClientView");
			Object.DontDestroyOnLoad((Object)(object)val);
			_canvas = val.AddComponent<Canvas>();
			_canvas.renderMode = (RenderMode)0;
			_canvas.sortingOrder = 1000;
			CanvasScaler obj = val.AddComponent<CanvasScaler>();
			obj.uiScaleMode = (ScaleMode)1;
			obj.referenceResolution = new Vector2(1920f, 1080f);
			obj.screenMatchMode = (ScreenMatchMode)0;
			obj.matchWidthOrHeight = 1f;
			GameObject val2 = MakeRect("Panel", val.transform);
			RectTransform component = val2.GetComponent<RectTransform>();
			Vector2 val3 = (component.pivot = Vector2.zero);
			Vector2 anchorMin = (component.anchorMax = val3);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(14f, 14f);
			component.sizeDelta = new Vector2(440f, 300f);
			val2.AddComponent<RectMask2D>();
			GameObject val5 = MakeRect("Content", val2.transform);
			_content = val5.GetComponent<RectTransform>();
			RectTransform content = _content;
			RectTransform content2 = _content;
			val3 = (_content.pivot = Vector2.zero);
			anchorMin = (content2.anchorMax = val3);
			content.anchorMin = anchorMin;
			_content.anchoredPosition = new Vector2(10f, 8f);
			_content.sizeDelta = new Vector2(420f, 0f);
			VerticalLayoutGroup obj2 = val5.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj2).childAlignment = (TextAnchor)6;
			((HorizontalOrVerticalLayoutGroup)obj2).spacing = 3f;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
			ContentSizeFitter obj3 = val5.AddComponent<ContentSizeFitter>();
			obj3.verticalFit = (FitMode)2;
			obj3.horizontalFit = (FitMode)0;
			((Behaviour)_canvas).enabled = _wantVisible;
			_built = true;
			Log.Info("AP client view built (font=" + (((Object)(object)_font != (Object)null) ? ((Object)_font).name : "default") + ").");
		}

		private static GameObject MakeRect(string name, Transform parent)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.AddComponent<RectTransform>();
			val.transform.SetParent(parent, false);
			return val;
		}

		private static TMP_FontAsset FindGameFont()
		{
			TextMeshProUGUI[] array = Resources.FindObjectsOfTypeAll<TextMeshProUGUI>();
			foreach (TextMeshProUGUI val in array)
			{
				if ((Object)(object)((TMP_Text)val).font != (Object)null)
				{
					return ((TMP_Text)val).font;
				}
			}
			return null;
		}
	}
	public class LastConnectionInfo
	{
		public string Host;

		public string Port;

		public string SlotName;

		public string Password;
	}
	public class FileWriter : MonoBehaviour
	{
		private const string LastConnectionFileName = "last_connection.txt";

		public static void WriteLastConnection(string host, int port, string slotName, string password)
		{
			try
			{
				string path = Application.persistentDataPath + "/last_connection.txt";
				List<string> list = new List<string>
				{
					host ?? "",
					port.ToString(),
					slotName ?? "",
					password ?? ""
				};
				File.WriteAllLines(path, list.ToArray());
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Failed to write last connection info: " + ex.Message));
			}
		}

		public static LastConnectionInfo ReadLastConnection()
		{
			try
			{
				string path = Application.persistentDataPath + "/last_connection.txt";
				if (!File.Exists(path))
				{
					return null;
				}
				string[] array = File.ReadAllLines(path);
				return new LastConnectionInfo
				{
					Host = ((array.Length != 0) ? array[0] : null),
					Port = ((array.Length > 1) ? array[1] : null),
					SlotName = ((array.Length > 2) ? array[2] : null),
					Password = ((array.Length > 3) ? array[3] : null)
				};
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Failed to read last connection info: " + ex.Message));
				return null;
			}
		}
	}
	public class GameHandler : MonoBehaviour
	{
		[HarmonyPatch(typeof(Collectible), "OnDone")]
		private class Collectible_OnDone_Patch
		{
			private static void Prefix()
			{
				if (PikunikuAPMod.SlotData.Coinsanity)
				{
					_suppressCoinCredit = true;
				}
			}

			private static void Postfix(Collectible __instance)
			{
				if (PikunikuAPMod.SlotData.Coinsanity)
				{
					_suppressCoinCredit = false;
					string text = CoinLocationName(__instance);
					if (TryGetLocationId(text, out var locId))
					{
						Log.Message($"Coinsanity check: '{text}' ({locId}) [{CoinLine(__instance)}]");
						PikunikuAPMod.ArchipelagoHandler?.CheckLocation(locId);
					}
					else
					{
						Log.Message("Coin picked up (unmapped): " + CoinLine(__instance));
					}
					__instance.Collected = false;
				}
			}
		}

		[HarmonyPatch(typeof(CoinsManager), "AddCredit")]
		private class CoinsManager_AddCredit_Patch
		{
			private static bool Prefix()
			{
				if (!_suppressCoinCredit)
				{
					return true;
				}
				_suppressCoinCredit = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(Collectible), "Start")]
		private class Collectible_Start_Reskin_Patch
		{
			private static void Postfix(Collectible __instance)
			{
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				MeshRenderer meshRenderer = __instance.meshRenderer;
				MeshFilter val = (((Object)(object)meshRenderer != (Object)null) ? ((Component)meshRenderer).GetComponent<MeshFilter>() : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				if ((Object)(object)_coinMat == (Object)null)
				{
					if ((Object)(object)_coinTex == (Object)null)
					{
						_coinTex = LoadEmbeddedTexture("PikunikuAPMod.Assets.pikuniku_coin_ap_logo.png");
					}
					if ((Object)(object)_coinTex == (Object)null)
					{
						return;
					}
					_coinMat = MakeUnlitMaterial(_coinTex);
				}
				if ((Object)(object)_coinQuad == (Object)null && (Object)(object)val.sharedMesh != (Object)null)
				{
					Bounds bounds = val.sharedMesh.bounds;
					_coinQuad = CreateQuadMesh(((Bounds)(ref bounds)).size);
				}
				if (!((Object)(object)_coinQuad == (Object)null))
				{
					val.sharedMesh = _coinQuad;
					((Renderer)meshRenderer).sharedMaterial = _coinMat;
				}
			}
		}

		[HarmonyPatch(typeof(GiftBox), "SetupTrophy")]
		private class GiftBox_SetupTrophy_Reskin_Patch
		{
			private static void Postfix(GiftBox __instance)
			{
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_014b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0153: Unknown result type (might be due to invalid IL or missing references)
				//IL_0158: Unknown result type (might be due to invalid IL or missing references)
				//IL_0160: Unknown result type (might be due to invalid IL or missing references)
				//IL_0165: Unknown result type (might be due to invalid IL or missing references)
				//IL_0169: Unknown result type (might be due to invalid IL or missing references)
				//IL_0173: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0202: Unknown result type (might be due to invalid IL or missing references)
				//IL_0212: Unknown result type (might be due to invalid IL or missing references)
				//IL_0217: Unknown result type (might be due to invalid IL or missing references)
				//IL_021f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0224: Unknown result type (might be due to invalid IL or missing references)
				//IL_0228: Unknown result type (might be due to invalid IL or missing references)
				//IL_0236: Unknown result type (might be due to invalid IL or missing references)
				//IL_0244: Unknown result type (might be due to invalid IL or missing references)
				//IL_0268: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance.transform_boxWrapper == (Object)null)
				{
					return;
				}
				List<MeshFilter> list = (from f in ((Component)__instance.transform_boxWrapper).GetComponentsInChildren<MeshFilter>(true)
					where (Object)(object)f.sharedMesh != (Object)null
					select f).ToList();
				if (list.Count == 0)
				{
					return;
				}
				List<MeshFilter> list2 = (from f in list.OrderByDescending((MeshFilter f) => MeshVolume(f.sharedMesh)).Take(2)
					orderby ((Component)f).transform.position.y descending
					select f).ToList();
				foreach (MeshFilter item in list)
				{
					if (!list2.Contains(item))
					{
						MeshRenderer component = ((Component)item).GetComponent<MeshRenderer>();
						if ((Object)(object)component != (Object)null)
						{
							((Renderer)component).enabled = false;
						}
					}
				}
				if (list2.Count == 1)
				{
					ApplyPresentSkin(list2[0], top: false);
					return;
				}
				MeshFilter val = list2[0];
				MeshFilter val2 = list2[1];
				Texture2D val3 = PresentTexture(top: true);
				Texture2D val4 = PresentTexture(top: false);
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val4 == (Object)null))
				{
					Vector3 lossyScale = ((Component)val).transform.lossyScale;
					Vector3 lossyScale2 = ((Component)val2).transform.lossyScale;
					Bounds bounds = val.sharedMesh.bounds;
					float num = ((Bounds)(ref bounds)).size.x * Mathf.Abs(lossyScale.x);
					float num2 = num * ((float)((Texture)val3).height / (float)((Texture)val3).width);
					float num3 = num * ((float)((Texture)val4).height / (float)((Texture)val4).width);
					ApplyPresentSkinSized(val, top: true, new Vector3(num / Mathf.Abs(lossyScale.x), num2 / Mathf.Abs(lossyScale.y), 0f));
					ApplyPresentSkinSized(val2, top: false, new Vector3(num / Mathf.Abs(lossyScale2.x), num3 / Mathf.Abs(lossyScale2.y), 0f));
					Vector3 position = ((Component)val).transform.position;
					Vector3 position2 = ((Component)val2).transform.position;
					position2.x = position.x;
					position2.z = position.z;
					position2.y = position.y - num2 * 0.5f - num3 * 0.5f;
					((Component)val2).transform.position = position2;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryManager), "SetupAnimObj")]
		private class InventoryManager_SetupAnimObj_Patch
		{
			private static void Postfix(InventoryManager __instance, Inventory_Object obj)
			{
				if (!((Object)(object)obj != (Object)null) || obj.UniqueID != 1358097203)
				{
					ApplyApPopupOverride(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryManager), "SetupAnimHat")]
		private class InventoryManager_SetupAnimHat_Patch
		{
			private static void Postfix(InventoryManager __instance)
			{
				ApplyApPopupOverride(__instance);
			}
		}

		[HarmonyPatch(typeof(Piku), "_KillCoroutine")]
		private class Piku_KillCoroutine_DeathLink_Patch
		{
			private static void Prefix(bool hasRespawnPos)
			{
				if (!hasRespawnPos)
				{
					PikunikuAPMod.ArchipelagoHandler?.OnPlayerGameOver();
				}
			}
		}

		[HarmonyPatch(typeof(Piku), "Kill", new Type[] { })]
		private class Piku_Kill_Patch
		{
			private static bool Prefix()
			{
				PikunikuAPMod.ArchipelagoHandler.SendDeath();
				return true;
			}
		}

		[HarmonyPatch(typeof(InventoryManager), "_AddHatWithAnimation")]
		private class InventoryManager_AddHatWithAnimation_Patch
		{
			private static bool Prefix(InventoryManager __instance, HatSO ObjectToAdd, bool hasBeenBought, ref IEnumerator __result)
			{
				if (!hasBeenBought)
				{
					return true;
				}
				if ((Object)(object)ObjectToAdd == (Object)null || !TryGetLocationId(HatLocationName(ObjectToAdd.UniqueID), out var _))
				{
					return true;
				}
				__instance.Hat_Add(ObjectToAdd, true);
				__result = ShopPurchaseNoop();
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryManager), "_AddObjectWithAnimation")]
		private class InventoryManager_AddObjectWithAnimation_Patch
		{
			private static bool Prefix(InventoryManager __instance, Inventory_Object ObjectToAdd, string WorldName, bool hasBeenBought, ref IEnumerator __result)
			{
				if (!hasBeenBought)
				{
					return true;
				}
				if ((Object)(object)ObjectToAdd == (Object)null || !TryGetLocationId(ObjectLocationName(ObjectToAdd.UniqueID), out var _))
				{
					return true;
				}
				__instance.Object_Add(ObjectToAdd, WorldName, true);
				__result = ShopPurchaseNoop();
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryManager), "Hat_Add")]
		private class InventoryManager_Hat_Add_Patch
		{
			private static bool Prefix(HatSO ObjectToAdd)
			{
				if ((Object)(object)ObjectToAdd == (Object)null)
				{
					return true;
				}
				if ((Object)(object)PikunikuAPMod.ItemHandler != (Object)null && PikunikuAPMod.ItemHandler.IsReceivingItem)
				{
					return true;
				}
				Log.Info($"Caught Hat Receipt: {((Object)ObjectToAdd).name} (ID: {ObjectToAdd.UniqueID})");
				string text = HatLocationName(ObjectToAdd.UniqueID);
				if (TryGetLocationId(text, out var locId))
				{
					Log.Info($"Sending AP Check for {text} ({locId})");
					PikunikuAPMod.ArchipelagoHandler.CheckLocation(locId);
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Piku), "SetDefaultProperties")]
		private class Piku_SetDefaultProperties_Patch
		{
			private static void Postfix(Piku __instance)
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0049: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				if (!PikunikuAPMod.ArchipelagoHandler.IsConnected)
				{
					return;
				}
				Color val = Color.HSVToRGB(Random.value, 0.75f, 0.9f);
				string pikuColor = PikunikuAPMod.SlotData.PikuColor;
				if (!(pikuColor == "0"))
				{
					Color val2 = default(Color);
					if (pikuColor == "1")
					{
						__instance.Set_BodyColor(val);
						__instance.default_bodyColor = val;
					}
					else if (ColorUtility.TryParseHtmlString(pikuColor, ref val2))
					{
						__instance.Set_BodyColor(val2);
						__instance.default_bodyColor = val2;
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryManager), "Object_Add")]
		private class InventoryManager_Object_Add_Patch
		{
			private static bool Prefix(Inventory_Object ObjectToAdd)
			{
				if ((Object)(object)ObjectToAdd == (Object)null)
				{
					return true;
				}
				if (ObjectToAdd.UniqueID == 1358097203)
				{
					return true;
				}
				if ((Object)(object)PikunikuAPMod.ItemHandler != (Object)null && PikunikuAPMod.ItemHandler.IsReceivingItem)
				{
					return true;
				}
				Log.Info($"Caught Object Receipt: {((Object)ObjectToAdd).name} (ID: {ObjectToAdd.UniqueID})");
				string text = ObjectLocationName(ObjectToAdd.UniqueID);
				if (TryGetLocationId(text, out var locId))
				{
					Log.Info($"Sending AP Check for {text} ({locId})");
					PikunikuAPMod.ArchipelagoHandler.CheckLocation(locId);
					if (ObjectToAdd.UniqueID == 1632897859)
					{
						_appleCheckIndex++;
					}
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(TrophiesManager), "CatchTrophy")]
		private class TrophiesManager_CatchTrophy_Patch
		{
			private static bool Prefix(Trophy trophy)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)trophy == (Object)null)
				{
					return true;
				}
				if ((Object)(object)PikunikuAPMod.ItemHandler != (Object)null && PikunikuAPMod.ItemHandler.IsReceivingItem)
				{
					return true;
				}
				Log.Info($"Caught Trophy Receipt: {((Object)trophy).name} (ID: {trophy.achievementID})");
				string text = TrophyLocationName(((object)Unsafe.As<Trophies, Trophies>(ref trophy.achievementID)/*cast due to .constrained prefix*/).ToString());
				if (TryGetLocationId(text, out var locId))
				{
					Log.Info($"Sending AP Check for {text} ({locId})");
					PikunikuAPMod.ArchipelagoHandler.CheckLocation(locId);
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(HatCatch), "CheckIfAlreadyCollected")]
		private class HatCatch_CheckIfAlreadyCollected_Patch
		{
			private static bool Prefix(ref bool __result)
			{
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(HatCatch), "Start")]
		private class HatCatch_Start_Patch
		{
			private static void Postfix(HatCatch __instance)
			{
				if ((Object)(object)__instance.hat != (Object)null && TryGetLocationId(HatLocationName(__instance.hat.UniqueID), out var locId) && IsChecked(locId))
				{
					__instance.DisableHat();
				}
			}
		}

		[HarmonyPatch(typeof(ObjectCatch), "Start")]
		private class ObjectCatch_Start_Patch
		{
			private static void Postfix(ObjectCatch __instance)
			{
				if ((Object)(object)__instance.obj == (Object)null)
				{
					return;
				}
				long locId;
				if (__instance.obj.UniqueID == 1632897859)
				{
					if (NextAppleLocationName() == null)
					{
						((Component)__instance).gameObject.SetActive(false);
					}
					else
					{
						__instance.Collected = false;
					}
				}
				else if (TryGetLocationId(ObjectLocationName(__instance.obj.UniqueID), out locId))
				{
					if (IsChecked(locId))
					{
						((Component)__instance).gameObject.SetActive(false);
					}
					else
					{
						__instance.Collected = false;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Mine_ComputerRoom), "Start")]
		private class Mine_ComputerRoom_Start_Patch
		{
			private static void Postfix(Mine_ComputerRoom __instance)
			{
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Expected O, but got Unknown
				if (!((Object)(object)__instance.worm == (Object)null) && TryGetLocationId("A Video Game", out var locId))
				{
					if 

websocket-sharp.dll

Decompiled 11 hours ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Text;
using System.Threading;
using WebSocketSharp.Net;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace WebSocketSharp
{
	internal class DllDirectory : IDisposable
	{
		private static object _lock = new object();

		private bool _disposed = false;

		private static string _oldDllDirectory = null;

		private DllDirectory()
		{
		}

		[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
		private static extern int GetDllDirectory(int nBufferLength, StringBuilder lpPathName);

		[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
		private static extern bool SetDllDirectory(string lpPathName);

		private static void set(string newDllDirectory)
		{
			if (_oldDllDirectory != null)
			{
				throw new InvalidOperationException("Please reset dll directory before setting it again!");
			}
			StringBuilder stringBuilder = new StringBuilder(10240);
			int dllDirectory = GetDllDirectory(10240, stringBuilder);
			if (dllDirectory > 10240)
			{
				throw new Exception("Could not SetDllDirectory");
			}
			string oldDllDirectory = stringBuilder.ToString(0, dllDirectory);
			SetDllDirectory(newDllDirectory);
			_oldDllDirectory = oldDllDirectory;
		}

		private static void reset()
		{
			if (_oldDllDirectory != null)
			{
				SetDllDirectory(_oldDllDirectory);
				_oldDllDirectory = null;
			}
		}

		internal static void Set(string newDllDirectory)
		{
			lock (_lock)
			{
				set(newDllDirectory);
			}
		}

		internal static void Reset()
		{
			lock (_lock)
			{
				reset();
			}
		}

		internal static DllDirectory Context(string newDllDirectory)
		{
			Monitor.Enter(_lock);
			try
			{
				set(newDllDirectory);
				return new DllDirectory();
			}
			catch (Exception ex)
			{
				Monitor.Exit(_lock);
				throw ex;
			}
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				try
				{
					_disposed = true;
					reset();
				}
				finally
				{
					Monitor.Exit(_lock);
				}
			}
		}

		~DllDirectory()
		{
			Dispose(disposing: false);
		}
	}
	public class MessageEventArgs : EventArgs
	{
		private byte[] _data;

		private OpCode _opcode;

		private string _str;

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

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

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

		public byte[] RawData => _data;

		public string Data
		{
			get
			{
				if (_str == null)
				{
					_str = Encoding.UTF8.GetString(_data);
				}
				return _str;
			}
		}

		internal MessageEventArgs(byte[] data, OpCode opcode)
		{
			_data = data;
			_opcode = opcode;
			_str = null;
		}
	}
	public class CloseEventArgs : EventArgs
	{
		private ushort _code;

		private string _reason;

		public ushort Code => _code;

		public string Reason => _reason;

		public bool WasClean => _code >= 1000 && _code != 1005;

		internal CloseEventArgs(ushort code, string reason)
		{
			_code = code;
			_reason = reason;
		}
	}
	public class ErrorEventArgs : EventArgs
	{
		private string _message;

		private Exception _exception;

		public string Message => _message;

		public Exception Exception => _exception;

		internal ErrorEventArgs(string message, Exception exception)
		{
			_message = message;
			_exception = exception;
		}
	}
	public static class Ext
	{
		public static bool IsNullOrEmpty(this string value)
		{
			return value == null || value.Length == 0;
		}
	}
}
namespace WebSocketSharp.Net
{
	public class ClientSslConfiguration
	{
		public SslProtocols EnabledSslProtocols
		{
			get
			{
				return SslProtocols.None;
			}
			set
			{
			}
		}
	}
}
namespace WebSocketSharp
{
	internal enum OpCode
	{
		Text = 1,
		Binary = 2,
		Ping = 8,
		Pong = 10
	}
	public class WebSocket : IDisposable
	{
		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		internal delegate void OnMessageCallback(IntPtr data, ulong len, int opCode);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		internal delegate void OnOpenCallback();

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		internal delegate void OnCloseCallback();

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		internal delegate void OnErrorCallback(IntPtr msg);

		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
		internal delegate void OnPongCallback(IntPtr data, ulong len);

		private Uri uri;

		private WebSocketWorker worker = null;

		private WebSocketEventDispatcher dispatcher = null;

		private object dispatcherLock = new object();

		private List<byte[]> pings = new List<byte[]>();

		private DateTime lastPong;

		private volatile WebSocketState readyState = WebSocketState.New;

		private string lastError;

		private int _id;

		private static object _lastIdLock = new object();

		private static int _lastId = 0;

		private UIntPtr ws;

		private OnMessageCallback messageHandler;

		private OnOpenCallback openHandler;

		private OnCloseCallback closeHandler;

		private OnErrorCallback errorHandler;

		private OnPongCallback pongHandler;

		internal const CallingConvention CALLING_CONVENTION = CallingConvention.Cdecl;

		internal const string DLL_NAME = "c-wspp.dll";

		public WebSocketState ReadyState => readyState;

		public bool IsAlive
		{
			get
			{
				if (readyState != WebSocketState.Open)
				{
					return false;
				}
				if (DateTime.UtcNow - lastPong < new TimeSpan(0, 0, 0, 0, 300))
				{
					return true;
				}
				Random random = new Random();
				byte[] array = new byte[16];
				random.NextBytes(array);
				try
				{
					pingBlocking(array);
					return true;
				}
				catch (InvalidOperationException ex)
				{
					Console.WriteLine(ex.ToString());
					return true;
				}
				catch (TimeoutException)
				{
				}
				catch (Exception ex3)
				{
					Console.WriteLine(ex3.ToString());
				}
				return false;
			}
		}

		public bool IsSecure => uri.Scheme.ToLower() == "wss";

		public Uri Url => uri;

		public ClientSslConfiguration SslConfiguration => new ClientSslConfiguration();

		internal static string directory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		public event EventHandler OnOpen;

		public event EventHandler<CloseEventArgs> OnClose;

		public event EventHandler<ErrorEventArgs> OnError;

		public event EventHandler<MessageEventArgs> OnMessage;

		public WebSocket(string uriString)
		{
			lock (_lastIdLock)
			{
				_id = _lastId + 1;
				_lastId = _id;
			}
			debug("new (\"" + uriString + "\")");
			uri = new Uri(uriString);
			ws = wspp_new_from(uriString, directory);
			setHandlers();
		}

		public WebSocket(string uriString, string[] protocols)
		{
			lock (_lastIdLock)
			{
				_id = _lastId + 1;
				_lastId = _id;
			}
			debug("new (\"" + uriString + "\", " + ((protocols != null) ? ("[" + string.Join(", ", protocols) + "]") : "null") + ")");
			uri = new Uri(uriString);
			ws = wspp_new_from(uriString, directory);
			setHandlers();
		}

		private void error(string message, Exception exception = null)
		{
			debug("Error: " + message);
			if (exception == null)
			{
				exception = new Exception(message);
			}
			ErrorEventArgs e = new ErrorEventArgs(message, exception);
			dispatcher.Enqueue(e);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			debug("disposing");
			if (!(ws != UIntPtr.Zero))
			{
				return;
			}
			clearHandlers();
			UIntPtr uIntPtr = ws;
			ws = UIntPtr.Zero;
			debug("shutting down");
			close(uIntPtr, 1001, "Going away");
			try
			{
				if (worker != null)
				{
					worker.Dispose();
				}
			}
			catch (Exception)
			{
			}
			worker = null;
			try
			{
				if (dispatcher != null)
				{
					dispatcher.Dispose();
				}
			}
			catch (InvalidOperationException)
			{
				WebSocketEventDispatcher tmp = dispatcher;
				new Thread((ThreadStart)delegate
				{
					try
					{
						tmp.Dispose();
					}
					catch (Exception)
					{
					}
				}).Start();
			}
			catch (Exception)
			{
			}
			dispatcher = null;
			debug("wspp_delete");
			wspp_delete(uIntPtr);
			openHandler = null;
			closeHandler = null;
			messageHandler = null;
			errorHandler = null;
			pongHandler = null;
			dispatcherLock = null;
		}

		~WebSocket()
		{
			Dispose(disposing: false);
		}

		private void debug(string msg)
		{
		}

		private static void sdebug(string msg)
		{
		}

		private void warn(string msg)
		{
			Console.WriteLine("WARNING: WebSocket " + _id + ": " + msg);
		}

		private void pingBlocking(byte[] data, int timeout = 15000)
		{
			if (worker.IsCurrentThread)
			{
				throw new InvalidOperationException("Can't wait for reply from worker thread");
			}
			lock (pings)
			{
				pings.Add(data);
			}
			Ping(data);
			for (int i = 0; i < timeout; i++)
			{
				Thread.Sleep(1);
				lock (pings)
				{
					bool flag = true;
					foreach (byte[] ping in pings)
					{
						if (ping == data)
						{
							flag = false;
							break;
						}
					}
					if (flag)
					{
						return;
					}
				}
			}
			lock (pings)
			{
				pings.Remove(data);
			}
			debug("pong timeout");
			throw new TimeoutException();
		}

		public void Connect()
		{
			lastError = "";
			connect();
			while (worker != null && worker.IsAlive && readyState != WebSocketState.Open)
			{
				Thread.Sleep(1);
			}
			if (readyState != WebSocketState.Open)
			{
				throw new Exception("Connect failed" + ((!(lastError == "")) ? (": " + lastError) : ""));
			}
		}

		public void ConnectAsync()
		{
			lastError = "";
			connect();
			if (readyState != WebSocketState.Open && readyState != WebSocketState.Connecting)
			{
				throw new Exception("Connect failed" + ((!(lastError == "")) ? (": " + lastError) : ""));
			}
		}

		private void connect()
		{
			if (readyState != WebSocketState.Closed && readyState != 0)
			{
				throw new InvalidOperationException("Invalid state: " + readyState);
			}
			if (readyState != 0)
			{
				Thread.Sleep(1);
			}
			debug("ReadyState = Connecting");
			readyState = WebSocketState.Connecting;
			if (ws == UIntPtr.Zero)
			{
				throw new ObjectDisposedException(GetType().FullName);
			}
			if (worker != null && !worker.IsAlive)
			{
				worker = null;
			}
			lock (dispatcherLock)
			{
				if (dispatcher == null)
				{
					debug("creating dispatcher");
					dispatcher = new WebSocketEventDispatcher();
					dispatcher.OnOpen += dispatchOnOpen;
					dispatcher.OnClose += dispatchOnClose;
					dispatcher.OnError += dispatchOnError;
					dispatcher.OnMessage += dispatchOnMessage;
					dispatcher.Start();
				}
			}
			debug("wspp_connect");
			wspp_connect(ws);
			if (worker == null)
			{
				debug("creating worker");
				worker = new WebSocketWorker(ws);
				worker.Start();
			}
			else
			{
				debug("worker already running");
			}
		}

		public void Close()
		{
			Close(1001);
		}

		public void Close(ushort code)
		{
			Close(code, "");
		}

		public void Close(ushort code, string reason)
		{
			debug("Close(" + code + ", \"" + reason + "\")");
			if (ws == UIntPtr.Zero)
			{
				throw new ObjectDisposedException(GetType().FullName);
			}
			debug("ReadyState = Closing");
			readyState = WebSocketState.Closing;
			close(ws, code, reason);
			if (worker.IsCurrentThread)
			{
				throw new InvalidOperationException("Can't wait for reply from worker thread");
			}
			while (worker != null && worker.IsAlive && readyState != WebSocketState.Closed)
			{
				Thread.Sleep(1);
			}
		}

		public void CloseAsync()
		{
			CloseAsync(1001);
		}

		public void CloseAsync(ushort code)
		{
			CloseAsync(code, "");
		}

		public void CloseAsync(ushort code, string reason)
		{
			debug("CloseAsync(" + code + ", \"" + reason + "\")");
			if (ws == UIntPtr.Zero)
			{
				throw new ObjectDisposedException(GetType().FullName);
			}
			debug("ReadyState = Closing");
			readyState = WebSocketState.Closing;
			close(ws, code, reason);
		}

		public void Send(string message)
		{
			if (ws == UIntPtr.Zero)
			{
				throw new ObjectDisposedException(GetType().FullName);
			}
			IntPtr intPtr = StringToHGlobalUTF8(message);
			WsppRes wsppRes = (WsppRes)wspp_send_text(ws, intPtr);
			Marshal.FreeHGlobal(intPtr);
			if (wsppRes != 0)
			{
				throw new Exception(Enum.GetName(typeof(WsppRes), wsppRes) ?? "Unknown error");
			}
		}

		public void Send(byte[] data)
		{
			if (ws == UIntPtr.Zero)
			{
				throw new ObjectDisposedException(GetType().FullName);
			}
			WsppRes wsppRes = (WsppRes)wspp_send_binary(ws, data, (ulong)data.Length);
			if (wsppRes != 0)
			{
				throw new Exception(Enum.GetName(typeof(WsppRes), wsppRes) ?? "Unknown error");
			}
		}

		public void SendAsync(string message, Action<bool> onComplete = null)
		{
			Send(message);
			onComplete?.Invoke(obj: true);
		}

		public void SendAsync(byte[] data, Action<bool> onComplete = null)
		{
			Send(data);
			onComplete?.Invoke(obj: true);
		}

		public void Ping(byte[] data)
		{
			if (ws == UIntPtr.Zero)
			{
				throw new ObjectDisposedException(GetType().FullName);
			}
			WsppRes wsppRes = (WsppRes)wspp_ping(ws, data, (ulong)data.Length);
			if (wsppRes != 0)
			{
				throw new Exception(Enum.GetName(typeof(WsppRes), wsppRes) ?? "Unknown error");
			}
		}

		private void dispatchOnOpen(object sender, EventArgs e)
		{
			if (this.OnOpen != null)
			{
				this.OnOpen(this, e);
			}
		}

		private void dispatchOnClose(object sender, CloseEventArgs e)
		{
			lock (dispatcherLock)
			{
				WebSocketEventDispatcher tmp = dispatcher;
				if (tmp != null)
				{
					dispatcher = null;
					new Thread((ThreadStart)delegate
					{
						tmp.Dispose();
					}).Start();
				}
				else
				{
					warn("duplicate close event");
				}
			}
			if (this.OnError != null)
			{
				new Thread((ThreadStart)delegate
				{
					Thread.Sleep(1);
					this.OnClose(this, e);
				}).Start();
			}
		}

		private void dispatchOnError(object sender, ErrorEventArgs e)
		{
			if (readyState == WebSocketState.Closed)
			{
				lock (dispatcherLock)
				{
					WebSocketEventDispatcher tmp = dispatcher;
					if (tmp != null)
					{
						dispatcher = null;
						new Thread((ThreadStart)delegate
						{
							tmp.Dispose();
						}).Start();
					}
					else
					{
						warn("duplicate close event");
					}
				}
			}
			if (readyState == WebSocketState.Closed)
			{
				if (this.OnError != null)
				{
					new Thread((ThreadStart)delegate
					{
						Thread.Sleep(1);
						this.OnError(this, e);
					}).Start();
				}
			}
			else if (this.OnError != null)
			{
				this.OnError(this, e);
			}
		}

		private void dispatchOnMessage(object sender, MessageEventArgs e)
		{
			if (this.OnMessage != null)
			{
				this.OnMessage(this, e);
			}
		}

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
		internal static extern UIntPtr wspp_new(IntPtr uri);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void wspp_delete(UIntPtr ws);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern ulong wspp_poll(UIntPtr ws);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern ulong wspp_run(UIntPtr ws);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern bool wspp_stopped(UIntPtr ws);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern int wspp_connect(UIntPtr ws);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern int wspp_close(UIntPtr ws, ushort code, IntPtr reason);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern int wspp_send_text(UIntPtr ws, IntPtr message);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern int wspp_send_binary(UIntPtr ws, byte[] data, ulong len);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern int wspp_ping(UIntPtr ws, byte[] data, ulong len);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void wspp_set_open_handler(UIntPtr ws, OnOpenCallback f);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void wspp_set_close_handler(UIntPtr ws, OnCloseCallback f);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void wspp_set_message_handler(UIntPtr ws, OnMessageCallback f);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void wspp_set_error_handler(UIntPtr ws, OnErrorCallback f);

		[DllImport("c-wspp.dll", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void wspp_set_pong_handler(UIntPtr ws, OnPongCallback f);

		internal static IntPtr StringToHGlobalUTF8(string s, out int length)
		{
			if (s == null)
			{
				length = 0;
				return IntPtr.Zero;
			}
			byte[] bytes = Encoding.UTF8.GetBytes(s);
			IntPtr intPtr = Marshal.AllocHGlobal(bytes.Length + 1);
			Marshal.Copy(bytes, 0, intPtr, bytes.Length);
			Marshal.WriteByte(intPtr, bytes.Length, 0);
			length = bytes.Length;
			return intPtr;
		}

		internal static IntPtr StringToHGlobalUTF8(string s)
		{
			int length;
			return StringToHGlobalUTF8(s, out length);
		}

		internal bool sequenceEqual(byte[] a, byte[] b)
		{
			if (a.Length != b.Length)
			{
				return false;
			}
			for (int i = 0; i < a.Length; i++)
			{
				if (a[i] != b[i])
				{
					return false;
				}
			}
			return true;
		}

		private void OpenHandler()
		{
			debug("on Open");
			if (!(ws == UIntPtr.Zero))
			{
				debug("ReadyState = Open");
				readyState = WebSocketState.Open;
				EventArgs e = new EventArgs();
				dispatcher.Enqueue(e);
			}
		}

		private void CloseHandler()
		{
			debug("on Close");
			if (!(ws == UIntPtr.Zero))
			{
				debug("ReadyState = Closed");
				readyState = WebSocketState.Closed;
				CloseEventArgs e = new CloseEventArgs(0, "");
				dispatcher.Enqueue(e);
			}
		}

		private void MessageHandler(IntPtr data, ulong len, int opCode)
		{
			debug("on Message");
			if (!(ws == UIntPtr.Zero))
			{
				if (len > int.MaxValue)
				{
					error("Received message that was too long");
					return;
				}
				byte[] array = new byte[(uint)len];
				Marshal.Copy(data, array, 0, (int)len);
				MessageEventArgs e = new MessageEventArgs(array, (OpCode)opCode);
				dispatcher.Enqueue(e);
			}
		}

		private void ErrorHandler(IntPtr msgPtr)
		{
			debug("on Error");
			if (!(ws == UIntPtr.Zero))
			{
				string text = "Unknown";
				if (msgPtr != IntPtr.Zero)
				{
					text = Marshal.PtrToStringAnsi(msgPtr);
				}
				if (readyState == WebSocketState.Connecting)
				{
					debug("ReadyState = Closed");
					readyState = WebSocketState.Closed;
				}
				else if (readyState == WebSocketState.Open)
				{
					Close();
				}
				lastError = text;
				error("Connect error: " + text);
			}
		}

		private void PongHandler(IntPtr data, ulong len)
		{
			byte[] array = new byte[(uint)len];
			Marshal.Copy(data, array, 0, (int)len);
			lock (pings)
			{
				foreach (byte[] ping in pings)
				{
					if (sequenceEqual(array, ping))
					{
						pings.Remove(ping);
						lastPong = DateTime.UtcNow;
						return;
					}
				}
			}
			MessageEventArgs e = new MessageEventArgs(array, OpCode.Pong);
			dispatcher.Enqueue(e);
		}

		private static UIntPtr wspp_new(string uriString)
		{
			IntPtr hglobal = StringToHGlobalUTF8(uriString);
			try
			{
				return wspp_new(hglobal);
			}
			finally
			{
				Marshal.FreeHGlobal(hglobal);
			}
		}

		private static UIntPtr wspp_new_from(string uriString, string dllDirectory)
		{
			sdebug("wspp_new(\"" + uriString + "\") in c-wspp.dll from " + dllDirectory);
			using (DllDirectory.Context(dllDirectory))
			{
				return wspp_new(uriString);
			}
		}

		private static void close(UIntPtr ws, ushort code, string reason)
		{
			sdebug("wspp_close(" + code + ", \"" + reason + "')");
			IntPtr intPtr = StringToHGlobalUTF8(reason);
			wspp_close(ws, code, intPtr);
			Marshal.FreeHGlobal(intPtr);
		}

		private void setHandlers()
		{
			openHandler = OpenHandler;
			closeHandler = CloseHandler;
			messageHandler = MessageHandler;
			errorHandler = ErrorHandler;
			pongHandler = PongHandler;
			wspp_set_open_handler(ws, openHandler);
			wspp_set_close_handler(ws, closeHandler);
			wspp_set_message_handler(ws, messageHandler);
			wspp_set_error_handler(ws, errorHandler);
			wspp_set_pong_handler(ws, pongHandler);
		}

		private void clearHandlers()
		{
			wspp_set_open_handler(ws, null);
			wspp_set_close_handler(ws, null);
			wspp_set_message_handler(ws, null);
			wspp_set_error_handler(ws, null);
			wspp_set_pong_handler(ws, null);
		}
	}
	internal enum WsppRes
	{
		OK = 0,
		InvalidState = 1,
		Unknown = -1
	}
	internal class WebSocketEventDispatcher : IDisposable
	{
		private Thread _thread;

		private bool _stop;

		private Queue<EventArgs> _queue;

		private int _id;

		private static object _lastIdLock = new object();

		private static int _lastId = 0;

		public bool IsCurrentThread => Thread.CurrentThread == _thread;

		public bool IsAlive => _thread.IsAlive;

		public event EventHandler OnOpen;

		public event EventHandler<CloseEventArgs> OnClose;

		public event EventHandler<ErrorEventArgs> OnError;

		public event EventHandler<MessageEventArgs> OnMessage;

		public WebSocketEventDispatcher()
		{
			lock (_lastIdLock)
			{
				_id = _lastId + 1;
				_lastId = _id;
			}
			_thread = new Thread(work);
			_stop = false;
			_queue = new Queue<EventArgs>();
		}

		public void Start()
		{
			_thread.Start();
		}

		public void Join()
		{
			_thread.Join();
		}

		private void debug(string msg)
		{
		}

		private void work()
		{
			debug("running");
			while (!_stop)
			{
				EventArgs eventArgs;
				lock (_queue)
				{
					eventArgs = ((_queue.Count <= 0) ? null : _queue.Dequeue());
				}
				if (eventArgs != null)
				{
					if (eventArgs is MessageEventArgs)
					{
						if (this.OnMessage != null)
						{
							this.OnMessage(this, (MessageEventArgs)eventArgs);
						}
					}
					else if (eventArgs is CloseEventArgs)
					{
						if (this.OnClose != null)
						{
							this.OnClose(this, (CloseEventArgs)eventArgs);
						}
					}
					else if (eventArgs is ErrorEventArgs)
					{
						if (this.OnError != null)
						{
							this.OnError(this, (ErrorEventArgs)eventArgs);
						}
					}
					else if (this.OnOpen != null)
					{
						this.OnOpen(this, eventArgs);
					}
				}
				else
				{
					Thread.Sleep(1);
				}
			}
			debug("stopped");
			_queue = null;
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (IsCurrentThread)
			{
				throw new InvalidOperationException("Can't dispose self");
			}
			debug("disposing");
			if (!_stop)
			{
				_stop = true;
				_thread.Join();
				debug("joined");
				_queue = null;
			}
		}

		~WebSocketEventDispatcher()
		{
			Dispose(disposing: false);
		}

		public void Enqueue(EventArgs e)
		{
			lock (_queue)
			{
				_queue.Enqueue(e);
			}
		}
	}
	public enum WebSocketState : ushort
	{
		New,
		Connecting,
		Open,
		Closing,
		Closed
	}
	internal class WebSocketWorker : IDisposable
	{
		private UIntPtr _ws;

		private Thread _thread;

		private bool _stop;

		private int _id;

		private static object _lastIdLock = new object();

		private static int _lastId = 0;

		public bool IsCurrentThread => Thread.CurrentThread == _thread;

		public bool IsAlive => _thread.IsAlive;

		public WebSocketWorker(UIntPtr ws)
		{
			lock (_lastIdLock)
			{
				_id = _lastId + 1;
				_lastId = _id;
			}
			_ws = ws;
			_thread = new Thread(work);
			_stop = false;
		}

		public void Start()
		{
			_thread.Start();
		}

		public void Join()
		{
			_thread.Join();
		}

		private void debug(string msg)
		{
		}

		private void work()
		{
			while (!_stop && !WebSocket.wspp_stopped(_ws))
			{
				WebSocket.wspp_poll(_ws);
				Thread.Sleep(1);
			}
			if (!WebSocket.wspp_stopped(_ws))
			{
				debug("stopping");
			}
			for (int i = 0; i < 1000; i++)
			{
				if (WebSocket.wspp_stopped(_ws))
				{
					break;
				}
				WebSocket.wspp_poll(_ws);
				Thread.Sleep(1);
			}
			debug("stopped");
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool disposing)
		{
			debug("disposing");
			if (!_stop)
			{
				_stop = true;
				_thread.Join();
				debug("joined");
			}
		}

		~WebSocketWorker()
		{
			Dispose(disposing: false);
		}
	}
}