Decompiled source of ULTRArchipelago v0.1.0

Archipelago.MultiClient.Net.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: Guid("35a803ad-85ed-42e9-b1e3-c6b72096f0c1")]
[assembly: InternalsVisibleTo("Archipelago.MultiClient.Net.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[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: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/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; }

		Task<RoomInfoPacket> ConnectAsync();

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

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

		private ConnectionInfoHelper connectionInfo;

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

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

		public IArchipelagoSocketHelper Socket { get; }

		public IReceivedItemsHelper Items { get; }

		public ILocationCheckHelper Locations { get; }

		public IPlayerHelper Players { get; }

		public IDataStorageHelper DataStorage { get; }

		public IConnectionInfoProvider ConnectionInfo => connectionInfo;

		public IRoomStateHelper RoomState { get; }

		public IMessageLogHelper MessageLog { get; }

		public IHintsHelper Hints { get; }

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

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

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

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

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

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

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

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

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

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

		void SetClientState(ArchipelagoClientState state);

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

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

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

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

		public int Team { get; }

		public int Slot { get; }

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

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

		public ConnectionRefusedError[] ErrorCodes { get; }

		public string[] Errors { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public byte R { get; set; }

		public byte G { get; set; }

		public byte B { get; set; }

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

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

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

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

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

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

	}
	public class DataStorageElement
	{
		internal DataStorageElementContext Context;

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

		internal DataStorageHelper.DataStorageUpdatedHandler Callbacks;

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

		private JToken cachedValue;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

		public long ItemId { get; }

		public long LocationId { get; }

		public PlayerInfo Player { get; }

		public ItemFlags Flags { get; }

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

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

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

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

		public string ItemGame { get; }

		public string LocationGame { get; }

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

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

		public bool IsReceiverRelatedToActivePlayer { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public NetworkVersion()
		{
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private Callback()
		{
		}

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

		internal JToken Value { get; set; }

		private AdditionalArgument()
		{
		}

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

		public long LocationId { get; set; }

		public int PlayerSlot { get; set; }

		public ItemFlags Flags { get; set; }

		public string ItemGame { get; set; }

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

		public PlayerInfo Player { get; set; }

		public string ItemName { get; set; }

		public string LocationName { get; set; }

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

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

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

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

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

		public ILocationCheckHelper Locations { get; set; }

		public IPlayerHelper PlayerHelper { get; set; }

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

		public long ItemId { get; }

		public int Player { get; }

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

		public int Player { get; }

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

		public MessagePartType Type { get; internal set; }

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

		public PaletteColor? PaletteColor { get; protected set; }

		public bool IsBackgroundColor { get; internal set; }

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

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

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

		public int SlotId { get; }

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

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

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

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

		public PlayerInfo Receiver { get; }

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer;

		public bool IsSenderTheActivePlayer => Sender == ActivePlayer;

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

		public ItemInfo Item { get; }

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

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

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

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

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

		public PlayerInfo Player { get; }

		public bool IsActivePlayer => Player == ActivePlayer;

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

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

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

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

		internal ArchipelagoSocketHelper(Uri hostUri)
			: base(CreateWebSocket(), 1024)
		{
			Uri = hostUri;
		}

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

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

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

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

		internal T Socket;

		private readonly int bufferSize;

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

		public event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived;

		public event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent;

		public event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived;

		public event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed;

		public event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		int Team { get; }

		int Slot { get; }

		string[] Tags { get; }

		ItemsHandlingFlags ItemsHandlingFlags { get; }

		string Uuid { get; }

		void UpdateConnectionOptions(string[] tags);

		void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags);

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

		public string Game { get; private set; }

		public int Team { get; private set; }

		public int Slot { get; private set; }

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

		public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; }

		public string Uuid { get; private set; }

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

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

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

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

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

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

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

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

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

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

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

		private readonly IArchipelagoSocketHelper socket;

		private readonly IConnectionInfoProvider connectionInfoProvider;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UltrakillArchipelago.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: ComVisible(false)]
[assembly: AssemblyCompany("UltrakillArchipelago")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2025 MaybeAshleyIdk")]
[assembly: AssemblyDescription("Archipelago client implementation for ULTRAKILL")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+e1b6d22dc47de1e27cafcd7c446b54d728ef875c")]
[assembly: AssemblyProduct("ULTRAKILL Archipelago Client Mod")]
[assembly: AssemblyTitle("UltrakillArchipelago")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 ArchipelagoULTRAKILL
{
	public static class AudioManager
	{
		private static readonly Dictionary<string, string> multiMusicBattle = new Dictionary<string, string>
		{
			["1"] = "Assets/Music/0-1.wav",
			["2"] = "Assets/Music/0-2.wav",
			["3"] = "Assets/Music/0-1.wav",
			["4"] = "Assets/Music/0-2.wav",
			["6B"] = "Assets/Music/1-1.wav",
			["7B"] = "Assets/Music/1-2 Noise Battle.wav",
			["8"] = "Assets/Music/1-3.wav",
			["10"] = "Assets/Music/2-1.wav",
			["11"] = "Assets/Music/2-2.wav",
			["12"] = "Assets/Music/2-3.wav",
			["14A"] = "Assets/Music/3-1 Guts.wav",
			["14B"] = "Assets/Music/3-1 Glory.wav",
			["16"] = "Assets/Music/4-1.wav",
			["17"] = "Assets/Music/4-2.wav",
			["18A"] = "Assets/Music/4-3 Phase 1.wav",
			["18B"] = "Assets/Music/4-3 Phase 2.wav",
			["18C"] = "Assets/Music/4-3 Phase 3.wav",
			["20"] = "Assets/Music/5-1.wav",
			["22A"] = "Assets/Music/5-3.wav",
			["22B"] = "Assets/Music/5-3 Aftermath.wav",
			["24A"] = "Assets/Music/6-1.wav",
			["26B"] = "Assets/Music/7-1.wav",
			["27A"] = "Assets/Music/7-2 Intro Battle.wav",
			["27B"] = "Assets/Music/7-2.wav",
			["28B"] = "Assets/Music/7-3.wav",
			["667A"] = "Assets/Music/P-2.wav"
		};

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

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

		public static AudioClip TestLoadAudioClip(string address)
		{
			//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)
			return Addressables.LoadAssetAsync<AudioClip>((object)address).WaitForCompletion();
		}

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

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

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

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

		public static void ChangeMusic()
		{
			if (Core.CurrentLevelInfo.Music == MusicType.Normal)
			{
				LoadMusicManagerTracks(Core.CurrentLevelInfo.Id.ToString());
			}
			else
			{
				string currentScene = SceneHelper.CurrentScene;
				if (currentScene == null)
				{
					return;
				}
				int length = currentScene.Length;
				if (length != 9)
				{
					return;
				}
				switch (currentScene[6])
				{
				default:
					return;
				case '0':
					if (!(currentScene == "Level 0-5"))
					{
						return;
					}
					foreach (AudioSource item in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if ((Object)(object)((Component)item).transform.parent != (Object)null && (((Object)((Component)item).transform.parent).name == "4 Contents" || ((Object)((Component)item).transform.parent).name == "4 Contents(Clone)") && ((Object)((Component)item).transform).name == "Music")
						{
							item.clip = LoadNewSingleTrack(item.clip, "5");
							((Component)((Component)item).transform.parent.Find("Enemies").Find("StatueEnemy (1)")).GetComponent<SoundChanger>().newSound = LoadNewSingleTrack(item.clip, "5");
						}
					}
					break;
				case '1':
					switch (currentScene)
					{
					default:
						return;
					case "Level 1-1":
						LoadMusicManagerTracks("6A", single: true);
						foreach (MusicChanger item2 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
						{
							if (((Object)((Component)item2).gameObject).name == "MusicChanger")
							{
								item2.clean = LoadNewCleanTrack(item2.clean, "6B");
								item2.battle = LoadNewBattleTrack(item2.battle, "6B");
							}
						}
						break;
					case "Level 1-2":
						LoadMusicManagerTracks("7A", single: true);
						foreach (MusicChanger item3 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
						{
							if (((Object)((Component)item3).gameObject).name == "MusicActivator")
							{
								item3.clean = LoadNewCleanTrack(item3.clean, "7B");
								item3.battle = LoadNewBattleTrack(item3.battle, "7B");
							}
						}
						break;
					case "Level 1-4":
						foreach (AudioSource item4 in Core.FindAllComponentsInCurrentScene<AudioSource>())
						{
							if (((Object)((Component)item4).gameObject).name == "Music - Clair de Lune")
							{
								item4.clip = LoadNewSingleTrack(item4.clip, "9A");
							}
							else if (((Object)((Component)item4).gameObject).name == "Music - Versus")
							{
								item4.clip = LoadNewSingleTrack(item4.clip, "9B");
							}
						}
						break;
					}
					break;
				case '2':
					if (!(currentScene == "Level 2-1"))
					{
						if (!(currentScene == "Level 2-4"))
						{
							return;
						}
						foreach (AudioSource item5 in Core.FindAllComponentsInCurrentScene<AudioSource>())
						{
							if (((Object)((Component)item5).gameObject).name == "BossMusic")
							{
								item5.clip = LoadNewSingleTrack(item5.clip, "13");
							}
						}
						break;
					}
					foreach (MusicChanger item6 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item6).gameObject).name == "Cube (1)")
						{
							item6.clean = LoadNewCleanTrack(item6.clean, "10");
							item6.battle = LoadNewBattleTrack(item6.battle, "10");
						}
					}
					break;
				case '3':
					if (!(currentScene == "Level 3-1"))
					{
						if (!(currentScene == "Level 3-2"))
						{
							return;
						}
						foreach (AudioSource item7 in Core.FindAllComponentsInCurrentScene<AudioSource>())
						{
							if (((Object)((Component)item7).gameObject).name == "Music 2")
							{
								item7.clip = LoadNewSingleTrack(item7.clip, "15A");
							}
							else if (((Object)((Component)item7).gameObject).name == "Music 3")
							{
								item7.clip = LoadNewSingleTrack(item7.clip, "15B");
							}
						}
						break;
					}
					LoadMusicManagerTracks("14A");
					foreach (MusicChanger item8 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item8).gameObject).name == "MusicChanger")
						{
							item8.clean = LoadNewCleanTrack(item8.clean, "14B");
							item8.battle = LoadNewBattleTrack(item8.battle, "14B");
						}
					}
					break;
				case '4':
					if (!(currentScene == "Level 4-3"))
					{
						if (!(currentScene == "Level 4-4"))
						{
							return;
						}
						foreach (AudioSource item9 in Core.FindAllComponentsInCurrentScene<AudioSource>())
						{
							if (((Object)((Component)item9).gameObject).name == "Versus 2")
							{
								item9.clip = LoadNewSingleTrack(item9.clip, "19");
							}
						}
						break;
					}
					foreach (MusicChanger item10 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item10).gameObject).name == "OnLight")
						{
							item10.clean = LoadNewCleanTrack(item10.clean, "18A");
							item10.battle = LoadNewBattleTrack(item10.battle, "18A");
						}
						else if (((Object)((Component)item10).gameObject).name == "Music Changer")
						{
							item10.clean = LoadNewCleanTrack(item10.clean, "18B");
							item10.battle = LoadNewBattleTrack(item10.battle, "18B");
						}
						else if (((Object)((Component)item10).gameObject).name == "Music Changer (Normal)")
						{
							item10.clean = LoadNewCleanTrack(item10.clean, "18B");
							item10.battle = LoadNewBattleTrack(item10.battle, "18B");
						}
						else if (((Object)((Component)item10).gameObject).name == "Music")
						{
							item10.clean = LoadNewCleanTrack(item10.clean, "18C");
							item10.battle = LoadNewBattleTrack(item10.battle, "18C");
						}
						else if (((Object)((Component)item10).gameObject).name == "Trigger (Fight)")
						{
							item10.clean = LoadNewSingleTrack(item10.clean, "18D");
							item10.battle = LoadNewSingleTrack(item10.battle, "18D");
							item10.boss = LoadNewSingleTrack(item10.boss, "18D");
						}
					}
					break;
				case '5':
					if (!(currentScene == "Level 5-3"))
					{
						return;
					}
					LoadMusicManagerTracks("22A");
					foreach (MusicChanger item11 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item11).gameObject).name == "InstantVer")
						{
							item11.clean = LoadNewCleanTrack(item11.clean, "22B");
							item11.battle = LoadNewBattleTrack(item11.battle, "22B");
						}
						else if (((Object)((Component)item11).gameObject).name == "NormalVer")
						{
							item11.clean = LoadNewCleanTrack(item11.clean, "22B");
							item11.battle = LoadNewBattleTrack(item11.battle, "22B");
						}
					}
					break;
				case '6':
					if (!(currentScene == "Level 6-1"))
					{
						if (!(currentScene == "Level 6-2"))
						{
							return;
						}
						foreach (AudioSource item12 in Core.FindAllComponentsInCurrentScene<AudioSource>())
						{
							if (((Object)((Component)item12).gameObject).name == "Organ")
							{
								item12.clip = LoadNewSingleTrack(item12.clip, "25A");
							}
							else if (((Object)((Component)item12).gameObject).name == "BossMusic")
							{
								item12.clip = LoadNewSingleTrack(item12.clip, "25B");
							}
						}
						break;
					}
					foreach (MusicChanger item13 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
					{
						if (((Object)((Component)item13).gameObject).name == "MusicChanger")
						{
							item13.clean = LoadNewCleanTrack(item13.clean, "24A");
							item13.battle = LoadNewBattleTrack(item13.battle, "24A");
						}
					}
					foreach (AudioSource item14 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item14).gameObject).name == "ClimaxMusic")
						{
							item14.clip = LoadNewSingleTrack(item14.clip, "24B");
						}
					}
					break;
				case '7':
					switch (currentScene)
					{
					default:
						return;
					case "Level 7-1":
						foreach (MusicChanger item15 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
						{
							if (((Object)item15).name == "LevelMusicStart")
							{
								item15.clean = LoadNewCleanTrack(item15.clean, "26B");
								item15.battle = LoadNewBattleTrack(item15.battle, "26B");
								item15.boss = LoadNewBattleTrack(item15.battle, "26B");
							}
						}
						foreach (AudioSource item16 in Core.FindAllComponentsInCurrentScene<AudioSource>())
						{
							if (((Object)item16).name == "IntroMusic")
							{
								item16.clip = LoadNewSingleTrack(item16.clip, "26A");
							}
							else if (((Object)item16).name == "BigJohnatronMusic")
							{
								item16.clip = LoadNewSingleTrack(item16.clip, "26C");
							}
							else if (((Object)item16).name == "MinotaurPhase1Music")
							{
								item16.clip = LoadNewSingleTrack(item16.clip, "26D");
							}
							else if (((Object)item16).name == "MinotaurPhase2Music")
							{
								item16.clip = LoadNewSingleTrack(item16.clip, "26E");
							}
						}
						break;
					case "Level 7-2":
						LoadMusicManagerTracks("27A");
						foreach (MusicChanger item17 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
						{
							if (((Object)item17).name == "MusicActivator")
							{
								item17.clean = LoadNewCleanTrack(item17.clean, "27B");
								item17.battle = LoadNewBattleTrack(item17.battle, "27B");
								item17.boss = LoadNewBattleTrack(item17.battle, "27B");
							}
						}
						break;
					case "Level 7-3":
						LoadMusicManagerTracks("28A", single: true);
						foreach (MusicChanger item18 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
						{
							if (((Object)item18).name == "SecondTrackStart")
							{
								item18.clean = LoadNewCleanTrack(item18.clean, "28B");
								item18.battle = LoadNewBattleTrack(item18.battle, "28B");
								item18.boss = LoadNewBattleTrack(item18.battle, "28B");
							}
						}
						break;
					}
					break;
				case 'P':
					if (!(currentScene == "Level P-1"))
					{
						if (!(currentScene == "Level P-2"))
						{
							return;
						}
						foreach (MusicChanger item19 in Core.FindAllComponentsInCurrentScene<MusicChanger>())
						{
							if (((Object)((Component)item19).gameObject).name == "DelayedMusicActivator")
							{
								item19.clean = LoadNewCleanTrack(item19.clean, "667A");
								item19.battle = LoadNewBattleTrack(item19.battle, "667A");
								item19.boss = LoadNewBattleTrack(item19.battle, "667A");
							}
						}
						foreach (AudioSource item20 in Core.FindAllComponentsInCurrentScene<AudioSource>())
						{
							if (((Object)((Component)item20).gameObject).name == "FleshPrison")
							{
								item20.clip = LoadNewSingleTrack(item20.clip, "667B");
							}
							else if (((Object)((Component)item20).gameObject).name == "Sisyphus")
							{
								item20.clip = LoadNewSingleTrack(item20.clip, "667C");
							}
						}
						break;
					}
					foreach (AudioSource item21 in Core.FindAllComponentsInCurrentScene<AudioSource>())
					{
						if (((Object)((Component)item21).gameObject).name == "Chaos")
						{
							item21.clip = LoadNewSingleTrack(item21.clip, "666A");
						}
						else if (((Object)((Component)item21).gameObject).name == "Music 3")
						{
							item21.clip = LoadNewSingleTrack(item21.clip, "666B");
						}
					}
					break;
				}
			}
			Core.Logger.LogInfo((object)"Music changed successfully.");
		}
	}
	public static class ColorRandomizer
	{
		public static void RandomizeGunColors()
		{
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", true);
			MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", true);
			for (int i = 1; i <= 5; i++)
			{
				for (int j = 1; j <= 2; j++)
				{
					if (j != 2 || (i != 4 && i != 5))
					{
						bool flag = false;
						if (j == 2)
						{
							flag = true;
						}
						for (int k = 1; k <= 3; k++)
						{
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"r"
							}), Random.Range(0f, 1f));
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"g"
							}), Random.Range(0f, 1f));
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"b"
							}), Random.Range(0f, 1f));
							MonoSingleton<PrefsManager>.Instance.SetFloat(string.Concat(new object[6]
							{
								"gunColor.",
								i.ToString(),
								".",
								k.ToString(),
								flag ? ".a" : ".",
								"a"
							}), Random.Range(0f, 1f));
						}
					}
				}
			}
			if (Core.IsPlaying)
			{
				MonoSingleton<GunColorController>.Instance.UpdateGunColors();
				GunColorTypeGetter[] array = Object.FindObjectsOfType<GunColorTypeGetter>();
				for (int l = 0; l < array.Length; l++)
				{
					array[l].UpdatePreview();
				}
			}
		}

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

			public static OnClick <>9__88_0;

			public static OnClick <>9__88_1;

			public static OnClick <>9__88_2;

			public static PostStringValueChangeEvent <>9__88_3;

			public static BoolValueChangeEventDelegate <>9__88_4;

			public static BoolValueChangeEventDelegate <>9__88_5;

			public static BoolValueChangeEventDelegate <>9__88_6;

			public static EnumValueChangeEventDelegate<LogFont> <>9__88_7;

			public static IntValueChangeEventDelegate <>9__88_8;

			public static IntValueChangeEventDelegate <>9__88_9;

			public static IntValueChangeEventDelegate <>9__88_10;

			public static OnClick <>9__88_11;

			public static OnClick <>9__88_12;

			public static OnClick <>9__88_13;

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

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

			internal void <Initialize>b__88_2()
			{
				if (Multiworld.Authenticated)
				{
					bool flag = (Core.data.deathLink = !Core.data.deathLink);
					if (flag)
					{
						Multiworld.EnableDeathLink();
					}
					else
					{
						Multiworld.DisableDeathLink();
					}
					deathLinkToggleButton.text = (flag ? "DISABLE DEATH LINK" : "ENABLE DEATH LINK");
					SyncDeathLinkThresholdFieldState();
				}
			}

			internal void <Initialize>b__88_3(string value)
			{
				if (Multiworld.Authenticated)
				{
					if (value != "")
					{
						Multiworld.Session.Say(value);
					}
					chat.value = "";
				}
			}

			internal void <Initialize>b__88_4(BoolValueChangeEvent e)
			{
				GameObject recentLocationContainer = UIManager.recentLocationContainer;
				if (recentLocationContainer != null)
				{
					recentLocationContainer.SetActive(e.value);
				}
			}

			internal void <Initialize>b__88_5(BoolValueChangeEvent e)
			{
				GameObject recentItemContainer = UIManager.recentItemContainer;
				if (recentItemContainer != null)
				{
					recentItemContainer.SetActive(e.value);
				}
			}

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

			internal void <Initialize>b__88_7(EnumValueChangeEvent<LogFont> e)
			{
				UIManager.SetLogFont(e.value, reset: true);
			}

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

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

			internal void <Initialize>b__88_10(IntValueChangeEvent e)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				((Graphic)UIManager.log).color = new Color(1f, 1f, 1f, (float)e.value / 100f);
			}

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

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

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

		private const string DisableDeathLinkText = "DISABLE DEATH LINK";

		private const string EnableDeathLinkText = "ENABLE DEATH LINK";

		private const int DefaultDeathLinkThreshold = 3;

		public static PluginConfigurator config;

		public static ConfigPanel playerPanel;

		public static ConfigHeader dataInfo;

		public static BoolField isConnected;

		public static StringField playerName;

		public static StringField serverAddress;

		public static StringField serverPassword;

		public static BoolField hintMode;

		public static ButtonField connectButton;

		public static ButtonField disconnectButton;

		public static ConfigHeader connectionInfo;

		private static ButtonField? deathLinkToggleButton;

		private static IntField? deathLinkThresholdField;

		public static StringField chat;

		public static StringField start;

		public static StringField goal;

		public static StringField goalProgress;

		public static BoolField perfectGoal;

		public static StringField locationsChecked;

		public static EnumField<EnemyOptions> enemyRewards;

		public static BoolField challengeRewards;

		public static BoolField pRankRewards;

		public static BoolField hankRewards;

		public static BoolField clashReward;

		public static BoolField fishRewards;

		public static BoolField cleanRewards;

		public static BoolField chessReward;

		public static BoolField rocketReward;

		public static EnumField<Fire2Options> randomizeFire2;

		public static EnumField<WeaponForm> revForm;

		public static EnumField<WeaponForm> shoForm;

		public static EnumField<WeaponForm> naiForm;

		public static BoolField randomizeSkulls;

		public static BoolField randomizeLimbo;

		public static BoolField randomizeViolence;

		public static BoolField musicRandomizer;

		public static BoolField cybergrindHints;

		public static BoolField deathLink;

		public static ConfigPanel uiPanel;

		public static BoolField showRecentLocations;

		public static BoolField showRecentItems;

		public static BoolField showLog;

		public static EnumField<LogFont> logFont;

		public static IntField logLines;

		public static IntField logFontSize;

		public static IntField logOpacity;

		public static ButtonField logClear;

		public static ConfigPanel colorPanel;

		public static EnumField<ColorOptions> uiColorRandomizer;

		public static EnumField<ColorOptions> gunColorRandomizer;

		public static ButtonField enableCustomButton;

		public static ButtonField disableCustomButton;

		public static ColorField APPlayerSelf;

		public static ColorField APPlayerOther;

		public static ColorField APItemAdvancement;

		public static ColorField APItemNeverExclude;

		public static ColorField APItemFiller;

		public static ColorField APItemTrap;

		public static ColorField APLocation;

		public static ColorField layer0Color;

		public static ColorField layer1Color;

		public static ColorField layer2Color;

		public static ColorField layer3Color;

		public static ColorField layer4Color;

		public static ColorField layer5Color;

		public static ColorField layer6Color;

		public static ColorField layer7Color;

		public static ColorField encore0Color;

		public static ColorField encore1Color;

		public static ColorField primeColor;

		public static ColorField altColor;

		public static ColorField blueSkullColor;

		public static ColorField redSkullColor;

		public static ColorField switchColor;

		public static ColorField pointsColor;

		public static ColorField dualwieldColor;

		public static ColorField doublejumpColor;

		public static ColorField confusionColor;

		public static ColorField trapColor;

		public static ButtonField thunderstoreButton;

		public static ButtonField githubButton;

		public static ButtonField discordButton;

		public static ButtonField poptrackerButton;

		public static int DeathLinkThreshold
		{
			get
			{
				IntField? obj = deathLinkThresholdField;
				if (obj == null)
				{
					return 3;
				}
				return obj.value;
			}
		}

		public static void Initialize()
		{
			//IL_0050: 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)
			//IL_0074: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Expected O, but got Unknown
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Expected O, but got Unknown
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Expected O, but got Unknown
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Expected O, but got Unknown
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Expected O, but got Unknown
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Expected O, but got Unknown
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Expected O, but got Unknown
			//IL_02dd: Expected O, but got Unknown
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Expected O, but got Unknown
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Expected O, but got Unknown
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Expected O, but got Unknown
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Expected O, but got Unknown
			//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Expected O, but got Unknown
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Expected O, but got Unknown
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Expected O, but got Unknown
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Expected O, but got Unknown
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c4: Expected O, but got Unknown
			//IL_04d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04da: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e6: Expected O, but got Unknown
			//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: Expected O, but got Unknown
			//IL_0519: Unknown result type (might be due to invalid IL or missing references)
			//IL_051e: Unknown result type (might be due to invalid IL or missing references)
			//IL_052a: Expected O, but got Unknown
			//IL_053b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0540: Unknown result type (might be due to invalid IL or missing references)
			//IL_054c: Expected O, but got Unknown
			//IL_055d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0562: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Expected O, but got Unknown
			//IL_0693: Unknown result type (might be due to invalid IL or missing references)
			//IL_0698: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a4: Expected O, but got Unknown
			//IL_06b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c6: Expected O, but got Unknown
			//IL_06d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_06dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e8: Expected O, but got Unknown
			//IL_06f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_070a: Expected O, but got Unknown
			//IL_071b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0720: Unknown result type (might be due to invalid IL or missing references)
			//IL_072c: Expected O, but got Unknown
			//IL_073d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0742: Unknown result type (might be due to invalid IL or missing references)
			//IL_074e: Expected O, but got Unknown
			//IL_075a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0770: Unknown result type (might be due to invalid IL or missing references)
			//IL_077a: Expected O, but got Unknown
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Expected O, but got Unknown
			//IL_07b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bd: Expected O, but got Unknown
			//IL_0793: Unknown result type (might be due to invalid IL or missing references)
			//IL_0798: Unknown result type (might be due to invalid IL or missing references)
			//IL_079e: Expected O, but got Unknown
			//IL_07f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0809: Unknown result type (might be due to invalid IL or missing references)
			//IL_0813: Expected O, but got Unknown
			//IL_07d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_07db: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e1: Expected O, but got Unknown
			//IL_082c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0831: Unknown result type (might be due to invalid IL or missing references)
			//IL_0837: Expected O, but got Unknown
			//IL_08c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ce: Expected O, but got Unknown
			//IL_090d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0917: Expected O, but got Unknown
			//IL_08e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f2: Expected O, but got Unknown
			//IL_0956: Unknown result type (might be due to invalid IL or missing references)
			//IL_0960: Expected O, but got Unknown
			//IL_0930: Unknown result type (might be due to invalid IL or missing references)
			//IL_0935: Unknown result type (might be due to invalid IL or missing references)
			//IL_093b: Expected O, but got Unknown
			//IL_0998: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a2: Expected O, but got Unknown
			//IL_0979: Unknown result type (might be due to invalid IL or missing references)
			//IL_097e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0984: Expected O, but got Unknown
			//IL_0a70: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a7a: Expected O, but got Unknown
			//IL_09bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_09c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_09c6: Expected O, but got Unknown
			//IL_0ab2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0abc: Expected O, but got Unknown
			//IL_0a93: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a98: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a9e: Expected O, but got Unknown
			//IL_0af1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b15: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b1b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b25: Expected O, but got Unknown
			//IL_0b43: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b49: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b53: Expected O, but got Unknown
			//IL_0b71: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b77: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b81: Expected O, but got Unknown
			//IL_0b9f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0baf: Expected O, but got Unknown
			//IL_0bcd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bd3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bdd: Expected O, but got Unknown
			//IL_0bfb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c01: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c0b: Expected O, but got Unknown
			//IL_0c29: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c2f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c39: Expected O, but got Unknown
			//IL_0c45: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c69: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c6f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c79: Expected O, but got Unknown
			//IL_0c97: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c9d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ca7: Expected O, but got Unknown
			//IL_0cc5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ccb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cd5: Expected O, but got Unknown
			//IL_0cf3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cf9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d03: Expected O, but got Unknown
			//IL_0d21: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d27: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d31: Expected O, but got Unknown
			//IL_0d4f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d55: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d5f: Expected O, but got Unknown
			//IL_0d7d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d83: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d8d: Expected O, but got Unknown
			//IL_0dab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0db1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0dbb: Expected O, but got Unknown
			//IL_0dd9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ddf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0de9: Expected O, but got Unknown
			//IL_0e07: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e0d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e17: Expected O, but got Unknown
			//IL_0e35: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e3b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e45: Expected O, but got Unknown
			//IL_0e63: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e69: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e73: Expected O, but got Unknown
			//IL_0e91: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e97: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ea1: Expected O, but got Unknown
			//IL_0ebf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ec5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ecf: Expected O, but got Unknown
			//IL_0eed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ef3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0efd: Expected O, but got Unknown
			//IL_0f1b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f21: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f2b: Expected O, but got Unknown
			//IL_0f49: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f4f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f59: Expected O, but got Unknown
			//IL_0f77: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f7d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0f87: Expected O, but got Unknown
			//IL_0fa5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fb5: Expected O, but got Unknown
			//IL_0fd3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fd9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0fe3: Expected O, but got Unknown
			//IL_0ad5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ada: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ae0: Expected O, but got Unknown
			if (config != null)
			{
				return;
			}
			config = PluginConfigurator.Create("Archipelago", "maybeAshleyIdk.ultrakillArchipelago");
			string text = Path.Combine(Core.workingDir, "icon.png");
			if (File.Exists(text))
			{
				config.SetIconWithURL(text);
			}
			new ConfigHeader(config.rootPanel, "ARCHIPELAGO", 24);
			playerPanel = new ConfigPanel(config.rootPanel, "PLAYER SETTINGS", "playerPanel");
			dataInfo = new ConfigHeader(config.rootPanel, "", 16);
			new ConfigHeader(config.rootPanel, "---", 24);
			uiPanel = new ConfigPanel(config.rootPanel, "UI SETTINGS", "uiPanel");
			colorPanel = new ConfigPanel(config.rootPanel, "COLOR SETTINGS", "colorPanel");
			isConnected = new BoolField(playerPanel, "CONNECTED TO SERVER?", "isConnected", false, false);
			((ConfigField)isConnected).interactable = false;
			playerName = new StringField(playerPanel, "NAME", "playerName", "V1", false, true);
			serverAddress = new StringField(playerPanel, "ADDRESS", "serverAddress", "archipelago.gg", false, true);
			serverPassword = new StringField(playerPanel, "PASSWORD", "serverPassword", "", true, true);
			hintMode = new BoolField(playerPanel, "HINT MODE", "hintMode", false, false);
			new ConfigHeader(playerPanel, "Hint mode disables all randomization, and allows connecting to other games' slots to unlock hints while playing The Cyber Grind.", 12, (TextAlignmentOptions)257);
			connectionInfo = new ConfigHeader(playerPanel, "", 16, (TextAlignmentOptions)258);
			connectButton = new ButtonField(playerPanel, "CONNECT", "connectButton");
			ButtonField obj = connectButton;
			object obj2 = <>c.<>9__88_0;
			if (obj2 == null)
			{
				OnClick val = delegate
				{
					if (Multiworld.Authenticated)
					{
						connectionInfo.text = "Already connected to server.";
					}
					else if (SceneHelper.CurrentScene != "Main Menu")
					{
						connectionInfo.text = "Can only connect to an Archipelago server on the main menu.";
					}
					else if ((GameProgressSaver.GetTutorial() || GameProgressSaver.GetIntro()) && !Core.DataExists() && !hintMode.value)
					{
						connectionInfo.text = "No Archipelago data found. Start a new save file before connecting.";
					}
					else if (Core.DataExists() && hintMode.value)
					{
						connectionInfo.text = "Can't use hint mode on a save file that already has randomizer data.";
					}
					else if (!Multiworld.Authenticated)
					{
						Core.data.slot_name = playerName.value;
						Core.data.host_name = serverAddress.value;
						Core.data.password = serverPassword.value;
						if (Core.data.password == "")
						{
							Core.data.password = null;
						}
						if (hintMode.value)
						{
							Multiworld.ConnectBK();
						}
						else
						{
							((MonoBehaviour)Core.mw).StartCoroutine("Connect");
						}
						SyncDeathLinkFieldsState();
					}
				};
				<>c.<>9__88_0 = val;
				obj2 = (object)val;
			}
			obj.onClick += (OnClick)obj2;
			disconnectButton = new ButtonField(playerPanel, "DISCONNECT", "disconnectButton");
			ButtonField obj3 = disconnectButton;
			object obj4 = <>c.<>9__88_1;
			if (obj4 == null)
			{
				OnClick val2 = delegate
				{
					//IL_003b: Unknown result type (might be due to invalid IL or missing references)
					if (Multiworld.Authenticated)
					{
						Multiworld.Disconnect();
						connectionInfo.text = "Disconnected from server.";
						SyncDeathLinkFieldsState();
						if (SceneHelper.CurrentScene == "Main Menu")
						{
							((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red;
						}
					}
				};
				<>c.<>9__88_1 = val2;
				obj4 = (object)val2;
			}
			obj3.onClick += (OnClick)obj4;
			deathLinkToggleButton = new ButtonField(playerPanel, Core.data.deathLink ? "DISABLE DEATH LINK" : "ENABLE DEATH LINK", "deathLinkToggleButton")
			{
				interactable = Multiworld.Authenticated
			};
			ButtonField? obj5 = deathLinkToggleButton;
			object obj6 = <>c.<>9__88_2;
			if (obj6 == null)
			{
				OnClick val3 = delegate
				{
					if (Multiworld.Authenticated)
					{
						bool flag = (Core.data.deathLink = !Core.data.deathLink);
						if (flag)
						{
							Multiworld.EnableDeathLink();
						}
						else
						{
							Multiworld.DisableDeathLink();
						}
						deathLinkToggleButton.text = (flag ? "DISABLE DEATH LINK" : "ENABLE DEATH LINK");
						SyncDeathLinkThresholdFieldState();
					}
				};
				<>c.<>9__88_2 = val3;
				obj6 = (object)val3;
			}
			obj5.onClick += (OnClick)obj6;
			deathLinkThresholdField = new IntField(playerPanel, "DEATH LINK THRESHOLD", "deathLinkThreshold", 3, 1, 999, true, true)
			{
				interactable = (((ConfigField)deathLinkToggleButton).interactable && !Core.data.deathLink)
			};
			chat = new StringField(playerPanel, "CHAT", "chat", "", true, false)
			{
				interactable = false
			};
			StringField obj7 = chat;
			object obj8 = <>c.<>9__88_3;
			if (obj8 == null)
			{
				PostStringValueChangeEvent val4 = delegate(string value)
				{
					if (Multiworld.Authenticated)
					{
						if (value != "")
						{
							Multiworld.Session.Say(value);
						}
						chat.value = "";
					}
				};
				<>c.<>9__88_3 = val4;
				obj8 = (object)val4;
			}
			obj7.postValueChangeEvent += (PostStringValueChangeEvent)obj8;
			new ConfigHeader(playerPanel, "-----", 24);
			start = new StringField(playerPanel, "START LEVEL", "start", "?", false, false)
			{
				interactable = false
			};
			goal = new StringField(playerPanel, "GOAL LEVEL", "goal", "?", false, false)
			{
				interactable = false
			};
			goalProgress = new StringField(playerPanel, "LEVELS COMPLETED", "goalProgress", "?", false, false)
			{
				interactable = false
			};
			perfectGoal = new BoolField(playerPanel, "PERFECT GOAL", "perfectGoal", false)
			{
				interactable = false
			};
			locationsChecked = new StringField(playerPanel, "LOCATIONS CHECKED", "locationsChecked", "?", false, false)
			{
				interactable = false
			};
			EnumField<EnemyOptions> obj9 = new EnumField<EnemyOptions>(playerPanel, "ENEMY REWARDS", "enemyRewards", EnemyOptions.Disabled, false);
			((ConfigField)obj9).interactable = false;
			enemyRewards = obj9;
			enemyRewards.SetEnumDisplayName(EnemyOptions.Disabled, "DISABLED");
			enemyRewards.SetEnumDisplayName(EnemyOptions.Bosses, "BOSSES");
			enemyRewards.SetEnumDisplayName(EnemyOptions.Extra, "EXTRA");
			enemyRewards.SetEnumDisplayName(EnemyOptions.All, "All");
			challengeRewards = new BoolField(playerPanel, "CHALLENGE REWARDS", "challengeRewards", false, false)
			{
				interactable = false
			};
			pRankRewards = new BoolField(playerPanel, "P RANK REWARDS", "pRankRewards", false, false)
			{
				interactable = false
			};
			hankRewards = new BoolField(playerPanel, "HANK REWARDS", "hankRewards", false, false)
			{
				interactable = false
			};
			clashReward = new BoolField(playerPanel, "RANDOMIZE CLASH MODE", "clashReward", false, false)
			{
				interactable = false
			};
			fishRewards = new BoolField(playerPanel, "FISH REWARDS", "fishRewards", false, false)
			{
				interactable = false
			};
			cleanRewards = new BoolField(playerPanel, "CLEANING REWARDS", "cleanRewards", false, false)
			{
				interactable = false
			};
			chessReward = new BoolField(playerPanel, "CHESS REWARD", "chessReward", false, false)
			{
				interactable = false
			};
			rocketReward = new BoolField(playerPanel, "ROCKET RACE REWARD", "rocketReward", false, false)
			{
				interactable = false
			};
			EnumField<Fire2Options> obj10 = new EnumField<Fire2Options>(playerPanel, "RANDOMIZE SECONDARY FIRE", "randomizeFire2", Fire2Options.Disabled);
			((ConfigField)obj10).interactable = false;
			randomizeFire2 = obj10;
			randomizeFire2.SetEnumDisplayName(Fire2Options.Disabled, "DISABLED");
			randomizeFire2.SetEnumDisplayName(Fire2Options.Split, "SPLIT");
			randomizeFire2.SetEnumDisplayName(Fire2Options.Progressive, "PROGRESSIVE");
			EnumField<WeaponForm> obj11 = new EnumField<WeaponForm>(playerPanel, "REVOLVER FORM", "revForm", WeaponForm.Standard);
			((ConfigField)obj11).interactable = false;
			revForm = obj11;
			revForm.SetEnumDisplayName(WeaponForm.Standard, "STANDARD");
			revForm.SetEnumDisplayName(WeaponForm.Alternate, "ALTERNATE");
			EnumField<WeaponForm> obj12 = new EnumField<WeaponForm>(playerPanel, "SHOTGUN FORM", "shoForm", WeaponForm.Standard);
			((ConfigField)obj12).interactable = false;
			shoForm = obj12;
			shoForm.SetEnumDisplayName(WeaponForm.Standard, "STANDARD");
			shoForm.SetEnumDisplayName(WeaponForm.Alternate, "ALTERNATE");
			EnumField<WeaponForm> obj13 = new EnumField<WeaponForm>(playerPanel, "NAILGUN FORM", "naiForm", WeaponForm.Standard);
			((ConfigField)obj13).interactable = false;
			naiForm = obj13;
			naiForm.SetEnumDisplayName(WeaponForm.Standard, "STANDARD");
			naiForm.SetEnumDisplayName(WeaponForm.Alternate, "ALTERNATE");
			randomizeSkulls = new BoolField(playerPanel, "RANDOMIZE SKULLS", "randomizeSkulls", false, false)
			{
				interactable = false
			};
			randomizeLimbo = new BoolField(playerPanel, "RANDOMIZE LIMBO SWITCHES", "randomizeLimbo", false, false)
			{
				interactable = false
			};
			randomizeViolence = new BoolField(playerPanel, "RANDOMIZE VIOLENCE SWITCHES", "randomizeViolence", false, false)
			{
				interactable = false
			};
			musicRandomizer = new BoolField(playerPanel, "MUSIC RANDOMIZER", "musicRandomizer", false, false)
			{
				interactable = false
			};
			cybergrindHints = new BoolField(playerPanel, "UNLOCK HINTS IN CYBERGRIND", "cybergrindHints", false, false)
			{
				interactable = false
			};
			deathLink = new BoolField(playerPanel, "DEATH LINK", "deathLink", false, false)
			{
				interactable = false
			};
			new ConfigHeader(uiPanel, "PAUSE MENU", 24);
			showRecentLocations = new BoolField(uiPanel, "SHOW RECENT LOCATIONS", "showRecentLocations", true);
			BoolField obj14 = showRecentLocations;
			object obj15 = <>c.<>9__88_4;
			if (obj15 == null)
			{
				BoolValueChangeEventDelegate val5 = delegate(BoolValueChangeEvent e)
				{
					GameObject recentLocationContainer = UIManager.recentLocationContainer;
					if (recentLocationContainer != null)
					{
						recentLocationContainer.SetActive(e.value);
					}
				};
				<>c.<>9__88_4 = val5;
				obj15 = (object)val5;
			}
			obj14.onValueChange += (BoolValueChangeEventDelegate)obj15;
			showRecentItems = new BoolField(uiPanel, "SHOW RECENT ITEMS", "showRecentItems", true);
			BoolField obj16 = showRecentItems;
			object obj17 = <>c.<>9__88_5;
			if (obj17 == null)
			{
				BoolValueChangeEventDelegate val6 = delegate(BoolValueChangeEvent e)
				{
					GameObject recentItemContainer = UIManager.recentItemContainer;
					if (recentItemContainer != null)
					{
						recentItemContainer.SetActive(e.value);
					}
				};
				<>c.<>9__88_5 = val6;
				obj17 = (object)val6;
			}
			obj16.onValueChange += (BoolValueChangeEventDelegate)obj17;
			new ConfigHeader(uiPanel, "LOG", 24);
			showLog = new BoolField(uiPanel, "SHOW LOG", "showLog", true, true);
			BoolField obj18 = showLog;
			object obj19 = <>c.<>9__88_6;
			if (obj19 == null)
			{
				BoolValueChangeEventDelegate val7 = delegate(BoolValueChangeEvent e)
				{
					((Component)UIManager.log).gameObject.SetActive(e.value);
				};
				<>c.<>9__88_6 = val7;
				obj19 = (object)val7;
			}
			obj18.onValueChange += (BoolValueChangeEventDelegate)obj19;
			logFont = new EnumField<LogFont>(uiPanel, "FONT", "logFont", LogFont.Pixel1);
			logFont.SetEnumDisplayName(LogFont.Pixel1, "fs Tahoma 8px");
			logFont.SetEnumDisplayName(LogFont.Pixel2, "VCR OSD MONO");
			logFont.SetEnumDisplayName(LogFont.SansSerif, "Roboto");
			logFont.onValueChange += delegate(EnumValueChangeEvent<LogFont> e)
			{
				UIManager.SetLogFont(e.value, reset: true);
			};
			logLines = new IntField(uiPanel, "NUMBER OF MESSAGES", "logLines", 5, 1, 16, true, true);
			IntField obj20 = logLines;
			object obj21 = <>c.<>9__88_8;
			if (obj21 == null)
			{
				IntValueChangeEventDelegate val8 = delegate(IntValueChangeEvent e)
				{
					UIManager.lines = e.value;
					while (Multiworld.messages.Count > e.value)
					{
						Multiworld.messages.RemoveAt(0);
					}
				};
				<>c.<>9__88_8 = val8;
				obj21 = (object)val8;
			}
			obj20.onValueChange += (IntValueChangeEventDelegate)obj21;
			logFontSize = new IntField(uiPanel, "FONT SIZE", "logFontSize", 20, 1, 32, true, true);
			IntField obj22 = logFontSize;
			object obj23 = <>c.<>9__88_9;
			if (obj23 == null)
			{
				IntValueChangeEventDelegate val9 = delegate(IntValueChangeEvent e)
				{
					((TMP_Text)UIManager.log).fontSize = e.value;
				};
				<>c.<>9__88_9 = val9;
				obj23 = (object)val9;
			}
			obj22.onValueChange += (IntValueChangeEventDelegate)obj23;
			logOpacity = new IntField(uiPanel, "OPACITY", "logOpacity", 100, 0, 100, true, true);
			IntField obj24 = logOpacity;
			object obj25 = <>c.<>9__88_10;
			if (obj25 == null)
			{
				IntValueChangeEventDelegate val10 = delegate(IntValueChangeEvent e)
				{
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					((Graphic)UIManager.log).color = new Color(1f, 1f, 1f, (float)e.value / 100f);
				};
				<>c.<>9__88_10 = val10;
				obj25 = (object)val10;
			}
			obj24.onValueChange += (IntValueChangeEventDelegate)obj25;
			logClear = new ButtonField(uiPanel, "CLEAR LOG", "logClear");
			ButtonField obj26 = logClear;
			object obj27 = <>c.<>9__88_11;
			if (obj27 == null)
			{
				OnClick val11 = delegate
				{
					UIManager.SetLogText("");
					Multiworld.messages.Clear();
				};
				<>c.<>9__88_11 = val11;
				obj27 = (object)val11;
			}
			obj26.onClick += (OnClick)obj27;
			uiColorRandomizer = new EnumField<ColorOptions>(colorPanel, "UI COLOR RANDOMIZER", "uiColorRandomizer", ColorOptions.Off, true);
			uiColorRandomizer.SetEnumDisplayName(ColorOptions.Off, "DISABLED");
			uiColorRandomizer.SetEnumDisplayName(ColorOptions.Once, "ONCE");
			uiColorRandomizer.SetEnumDisplayName(ColorOptions.EveryLoad, "EVERY NEW LEVEL LOADED");
			gunColorRandomizer = new EnumField<ColorOptions>(colorPanel, "GUN COLOR RANDOMIZER", "gunColorRandomizer", ColorOptions.Off, true);
			gunColorRandomizer.SetEnumDisplayName(ColorOptions.Off, "DISABLED");
			gunColorRandomizer.SetEnumDisplayName(ColorOptions.Once, "ONCE");
			gunColorRandomizer.SetEnumDisplayName(ColorOptions.EveryLoad, "EVERY NEW LEVEL LOADED");
			enableCustomButton = new ButtonField(colorPanel, "ENABLE ALL CUSTOM WEAPON COLORS", "enableCustomButton");
			ButtonField obj28 = enableCustomButton;
			object obj29 = <>c.<>9__88_12;
			if (obj29 == null)
			{
				OnClick val12 = delegate
				{
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", true);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", true);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", true);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", true);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", true);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", true);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", true);
				};
				<>c.<>9__88_12 = val12;
				obj29 = (object)val12;
			}
			obj28.onClick += (OnClick)obj29;
			disableCustomButton = new ButtonField(colorPanel, "DISABLE ALL CUSTOM WEAPON COLORS", "disableCustomButton");
			ButtonField obj30 = disableCustomButton;
			object obj31 = <>c.<>9__88_13;
			if (obj31 == null)
			{
				OnClick val13 = delegate
				{
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.1.a", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.2", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.3.a", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.4", false);
					MonoSingleton<PrefsManager>.Instance.SetBool("gunColorType.5", false);
				};
				<>c.<>9__88_13 = val13;
				obj31 = (object)val13;
			}
			obj30.onClick += (OnClick)obj31;
			new ConfigHeader(colorPanel, "ARCHIPELAGO COLORS", 24);
			APPlayerSelf = new ColorField(colorPanel, "PLAYER (YOU)", "APPlayerSelf", new Color(0.93f, 0f, 0.93f), true);
			APPlayerOther = new ColorField(colorPanel, "PLAYER (OTHERS)", "APPlayerOther", new Color(0.98f, 0.98f, 0.82f), true);
			APItemFiller = new ColorField(colorPanel, "ITEM (FILLER)", "APItemFiller", new Color(0f, 0.93f, 0.93f), true);
			APItemNeverExclude = new ColorField(colorPanel, "ITEM (USEFUL)", "APItemNeverExclude", new Color(0.43f, 0.55f, 0.91f), true);
			APItemAdvancement = new ColorField(colorPanel, "ITEM (PROGRESSION)", "APItemAdvancement", new Color(0.69f, 0.6f, 0.94f), true);
			APItemTrap = new ColorField(colorPanel, "ITEM (TRAP)", "APItemTrap", new Color(0.98f, 0.5f, 0.45f), true);
			APLocation = new ColorField(colorPanel, "LOCATION", "APLocation", new Color(0f, 1f, 0.5f), true);
			new ConfigHeader(colorPanel, "ITEM / LOCATION COLORS", 24);
			layer0Color = new ColorField(colorPanel, "LAYER 0", "layer0Color", new Color(1f, 0.5f, 0.25f), true);
			layer1Color = new ColorField(colorPanel, "LAYER 1", "layer1Color", new Color(0.2667f, 1f, 0.2706f), true);
			layer2Color = new ColorField(colorPanel, "LAYER 2", "layer2Color", new Color(0.765f, 0.25f, 1f), true);
			layer3Color = new ColorField(colorPanel, "LAYER 3", "layer3Color", new Color(1f, 0.9479f, 0.8566f), true);
			layer4Color = new ColorField(colorPanel, "LAYER 4", "layer4Color", new Color(1f, 1f, 0.25f), true);
			layer5Color = new ColorField(colorPanel, "LAYER 5", "layer5Color", new Color(0.251f, 0.9059f, 1f), true);
			layer6Color = new ColorField(colorPanel, "LAYER 6", "layer6Color", new Color(1f, 0.2353f, 0.2353f), true);
			layer7Color = new ColorField(colorPanel, "LAYER 7", "layer7Color", new Color(0.8f, 0.8f, 0.8f), true);
			encore0Color = new ColorField(colorPanel, "ENCORE 0", "encore0Color", new Color(0.6431f, 0.8745f, 0.9882f), true);
			encore1Color = new ColorField(colorPanel, "ENCORE 1", "encore1Color", new Color(0.5f, 0.5f, 0.5f), true);
			primeColor = new ColorField(colorPanel, "PRIME SANCTUMS", "primeColor", new Color(1f, 0.2353f, 0.2353f), true);
			altColor = new ColorField(colorPanel, "ALTERNATE WEAPON", "altColor", new Color(1f, 0.65f, 0f), true);
			blueSkullColor = new ColorField(colorPanel, "BLUE SKULL", "blueSkullColor", new Color(0.251f, 0.9059f, 1f), true);
			redSkullColor = new ColorField(colorPanel, "RED SKULL", "redSkullColor", new Color(1f, 0.2353f, 0.2353f), true);
			switchColor = new ColorField(colorPanel, "SWITCH", "switchColor", new Color(0.25f, 0.3f, 1f), true);
			pointsColor = new ColorField(colorPanel, "POINTS", "pointsColor", new Color(1f, 0.65f, 0f), true);
			dualwieldColor = new ColorField(colorPanel, "DUAL WIELD", "dualwieldColor", new Color(1f, 1f, 0.25f), true);
			doublejumpColor = new ColorField(colorPanel, "AIR JUMP", "doublejumpColor", new Color(1f, 1f, 0.6f), true);
			confusionColor = new ColorField(colorPanel, "CONFUSING AURA", "confusionColor", new Color(0.8242f, 1f, 0.1289f), true);
			trapColor = new ColorField(colorPanel, "TRAP", "trapColor", new Color(0.7f, 0.7f, 0.7f), true);
		}

		private static void SyncDeathLinkFieldsState()
		{
			SyncDeathLinkToggleButtonState();
			SyncDeathLinkThresholdFieldState();
		}

		private static void SyncDeathLinkToggleButtonState()
		{
			ButtonField val = deathLinkToggleButton;
			if (val != null)
			{
				((ConfigField)val).interactable = Multiworld.Authenticated;
				val.text = (Core.data.deathLink ? "DISABLE DEATH LINK" : "ENABLE DEATH LINK");
			}
		}

		private static void SyncDeathLinkThresholdFieldState()
		{
			IntField val = deathLinkThresholdField;
			if (val != null)
			{
				ButtonField val2 = deathLinkToggleButton;
				((ConfigField)val).interactable = val2 != null && ((ConfigField)val2).interactable && !Core.data.deathLink;
			}
		}

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

		public static void LoadStats()
		{
			dataInfo.text = Core.data.ToString();
			start.value = Core.data.start;
			goal.value = Core.data.goal;
			goalProgress.value = $"{Core.data.completedLevels.Count} / {Core.data.goalRequirement}";
			perfectGoal.value = Core.data.perfectGoal;
			string arg = ((LocationManager.locations.Count == 0) ? "?" : LocationManager.locations.Count.ToString());
			locationsChecked.value = $"{[email protected]} / {arg}";
			enemyRewards.value = Core.data.enemyRewards;
			challengeRewards.value = Core.data.challengeRewards;
			pRankRewards.value = Core.data.pRankRewards;
			hankRewards.value = Core.data.hankRewards;
			clashReward.value = Core.data.clashReward;
			fishRewards.value = Core.data.fishRewards;
			cleanRewards.value = Core.data.cleanRewards;
			chessReward.value = Core.data.chessReward;
			rocketReward.value = Core.data.rocketReward;
			randomizeFire2.value = Core.data.randomizeFire2;
			revForm.value = Core.data.revForm;
			shoForm.value = Core.data.shoForm;
			naiForm.value = Core.data.naiForm;
			randomizeSkulls.value = Core.data.randomizeSkulls;
			randomizeLimbo.value = Core.data.l1switch;
			randomizeViolence.value = Core.data.l7switch;
			musicRandomizer.value = Core.data.musicRandomizer;
			cybergrindHints.value = Core.data.cybergrindHints;
			deathLink.value = Core.data.deathLink;
			SyncDeathLinkFieldsState();
		}

		public static void ResetStatsDefaults()
		{
			if ((GameProgressSaver.GetTutorial() || GameProgressSaver.GetIntro()) && !Core.DataExists())
			{
				dataInfo.text = "Current slot is not randomized.";
			}
			else
			{
				dataInfo.text = Core.data.ToString();
			}
			start.value = "?";
			goal.value = "?";
			goalProgress.value = "?";
			perfectGoal.value = false;
			locationsChecked.value = "?";
			enemyRewards.value = EnemyOptions.Disabled;
			challengeRewards.value = false;
			pRankRewards.value = false;
			hankRewards.value = false;
			clashReward.value = false;
			fishRewards.value = false;
			cleanRewards.value = false;
			chessReward.value = false;
			rocketReward.value = false;
			randomizeFire2.value = Fire2Options.Disabled;
			revForm.value = WeaponForm.Standard;
			shoForm.value = WeaponForm.Standard;
			naiForm.value = WeaponForm.Standard;
			randomizeSkulls.value = false;
			randomizeLimbo.value = false;
			randomizeViolence.value = false;
			musicRandomizer.value = false;
			cybergrindHints.value = false;
			deathLink.value = false;
		}
	}
	[BepInPlugin("maybeAshleyIdk.ultrakillArchipelago", "Archipelago Client", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("trpg.archipelagoultrakill")]
	public class Core : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <ApplyLoadout>d__65 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public WeaponLoadout loadout;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitUntil((Func<bool>)(() => Multiworld.Session.Items.Index == data.index && LocationManager.itemQueue.Count == 0));
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					loadout.Set();
					Logger.LogInfo((object)"Set loadout");
					return false;
				}
			}

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

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

		public const string PluginGUID = "maybeAshleyIdk.ultrakillArchipelago";

		public const string PluginName = "Archipelago Client";

		public const string PluginVersion = "0.1.0";

		public static string workingPath;

		public static string workingDir;

		public static GameObject obj;

		public static UIManager uim;

		public static Multiworld mw;

		public static Data data = new Data();

		public static bool firstTimeLoad = false;

		public static readonly List<LevelInfo> levelInfos = new List<LevelInfo>
		{
			new LevelInfo("0-1", 1, 0, hasSecrets: true, MusicType.Normal, SkullsType.None),
			new LevelInfo("0-2", 2, 0, hasSecrets: true, MusicType.Normal, SkullsType.Normal, new List<string> { "2_b" }),
			new LevelInfo("0-3", 3, 0, hasSecrets: true, MusicType.Normal, SkullsType.None),
			new LevelInfo("0-4", 4, 0, hasSecrets: true, MusicType.Normal, SkullsType.None),
			new LevelInfo("0-5", 5, 0, hasSecrets: false, MusicType.Special2, SkullsType.None),
			new LevelInfo("1-1", 6, 1, hasSecrets: true, MusicType.Special, SkullsType.Normal, new List<string> { "6_b", "6_r" }),
			new LevelInfo("1-2", 7, 1, hasSecrets: true, MusicType.Special, SkullsType.Normal, new List<string> { "7_r", "7_b" }),
			new LevelInfo("1-3", 8, 1, hasSecrets: true, MusicType.Normal, SkullsType.Normal, new List<string> { "8_r", "8_b" }),
			new LevelInfo("1-4", 9, 1, hasSecrets: false, MusicType.Special, SkullsType.Special),
			new LevelInfo("2-1", 10, 2, hasSecrets: true, MusicType.Special, SkullsType.None),
			new LevelInfo("2-2", 11, 2, hasSecrets: true, MusicType.Normal, SkullsType.None),
			new LevelInfo("2-3", 12, 2, hasSecrets: true, MusicType.Normal, SkullsType.Normal, new List<string> { "12_r", "12_b" }),
			new LevelInfo("2-4", 13, 2, hasSecrets: false, MusicType.Special, SkullsType.Normal, new List<string> { "13_r", "13_b" }),
			new LevelInfo("3-1", 14, 3, hasSecrets: true, MusicType.Special, SkullsType.None),
			new LevelInfo("3-2", 15, 3, hasSecrets: false, MusicType.Special, SkullsType.None),
			new LevelInfo("4-1", 16, 4, hasSecrets: true, MusicType.Normal, SkullsType.None),
			new LevelInfo("4-2", 17, 4, hasSecrets: true, MusicType.Normal, SkullsType.Normal, new List<string> { "17_r", "17_b" }),
			new LevelInfo("4-3", 18, 4, hasSecrets: true, MusicType.Special, SkullsType.Normal, new List<string> { "18_b" }),
			new LevelInfo("4-4", 19, 4, hasSecrets: false, MusicType.Special, SkullsType.Normal, new List<string> { "19_b" }),
			new LevelInfo("5-1", 20, 5, hasSecrets: true, MusicType.Normal, SkullsType.Special),
			new LevelInfo("5-2", 21, 5, hasSecrets: true, MusicType.Skip, SkullsType.Normal, new List<string> { "21_r", "21_b" }),
			new LevelInfo("5-3", 22, 5, hasSecrets: true, MusicType.Special, SkullsType.Normal, new List<string> { "22_r", "22_b" }),
			new LevelInfo("5-4", 23, 5, hasSecrets: false, MusicType.Skip, SkullsType.None),
			new LevelInfo("6-1", 24, 6, hasSecrets: true, MusicType.Special, SkullsType.Normal, new List<string> { "24_r" }),
			new LevelInfo("6-2", 25, 6, hasSecrets: false, MusicType.Special, SkullsType.None),
			new LevelInfo("7-1", 26, 7, hasSecrets: true, MusicType.Special, SkullsType.Normal, new List<string> { "26_b", "26_r" }),
			new LevelInfo("7-2", 27, 7, hasSecrets: true, MusicType.Special, SkullsType.Normal, new List<string> { "27_r" }),
			new LevelInfo("7-3", 28, 7, hasSecrets: true, MusicType.Special, SkullsType.None),
			new LevelInfo("7-4", 29, 7, hasSecrets: false, MusicType.Skip, SkullsType.None),
			new LevelInfo("0-E", 100, 0, hasSecrets: false, MusicType.Skip, SkullsType.Normal, new List<string> { "100_r", "100_b" }),
			new LevelInfo("1-E", 101, 1, hasSecrets: false, MusicType.Skip, SkullsType.Normal, new List<string> { "101_b", "101_r" }),
			new LevelInfo("P-1", 666, 3, hasSecrets: false, MusicType.Special, SkullsType.None),
			new LevelInfo("P-2", 667, 6, hasSecrets: false, MusicType.Special, SkullsType.Normal, new List<string> { "667_b" })
		};

		public static readonly List<LevelInfo> secretMissionInfos = new List<LevelInfo>
		{
			new LevelInfo("0-S", 0, 0, hasSecrets: false, MusicType.Skip, SkullsType.Normal, new List<string> { "0S_r", "0S_b" }),
			new LevelInfo("1-S", 0, 1, hasSecrets: false, MusicType.Skip, SkullsType.None),
			new LevelInfo("2-S", 0, 2, hasSecrets: false, MusicType.Skip, SkullsType.None),
			new LevelInfo("4-S", 0, 4, hasSecrets: false, MusicType.Skip, SkullsType.None),
			new LevelInfo("5-S", 0, 5, hasSecrets: false, MusicType.Skip, SkullsType.None),
			new LevelInfo("7-S", 0, 7, hasSecrets: false, MusicType.Skip, SkullsType.Normal, new List<string> { "7S_b", "7S_r" })
		};

		public static readonly Dictionary<string, int> shopPrices = new Dictionary<string, int>
		{
			["rev2"] = 7500,
			["rev1"] = 12500,
			["sho1"] = 12500,
			["sho2"] = 25000,
			["nai1"] = 25000,
			["nai2"] = 35000,
			["rai1"] = 100000,
			["rai2"] = 100000,
			["rock1"] = 75000,
			["rock2"] = 75000
		};

		public static ManualLogSource Logger { get; } = Logger.CreateLogSource("Archipelago");


		public static Logger PLogger { get; } = new Logger("Archipelago");


		public static Core Instance { get; private set; }

		public static bool IsInIntro => GameStateManager.Instance.IsStateActive("intro");

		public static bool IsPitFalling => GameStateManager.Instance.IsStateActive("pit-falling");

		public static bool IsPaused
		{
			get
			{
				if (!GameStateManager.Instance.IsStateActive("pause"))
				{
					return GameStateManager.Instance.IsStateActive("pit-falling");
				}
				return true;
			}
		}

		public static bool IsInLevel
		{
			get
			{
				if (!GameStateManager.Instance.IsStateActive("main-menu"))
				{
					return !GameStateManager.Instance.IsStateActive("intro");
				}
				return false;
			}
		}

		public static bool IsPlaying
		{
			get
			{
				if (IsInLevel && !IsPaused)
				{
					return Object.op_Implicit((Object)(object)PlayerHelper.Instance);
				}
				return false;
			}
		}

		public static bool CanGetWeapon
		{
			get
			{
				if (IsInLevel && Object.op_Implicit((Object)(object)PlayerHelper.Instance))
				{
					return Object.op_Implicit((Object)(object)MonoSingleton<GunSetter>.Instance);
				}
				return false;
			}
		}

		public static bool HasNoArms
		{
			get
			{
				if (!data.hasArm)
				{
					return GameProgressSaver.GetGeneralProgress().arm1 < 1;
				}
				return false;
			}
		}

		public static List<string> AllLevels
		{
			get
			{
				List<string> list = new List<string>();
				foreach (LevelInfo levelInfo in levelInfos)
				{
					list.Add(levelInfo.Name);
				}
				return list;
			}
		}

		public static bool CurrentLevelHasInfo
		{
			get
			{
				if (SceneHelper.CurrentScene.Contains("-S"))
				{
					return true;
				}
				if (SceneHelper.CurrentScene.Contains("Level "))
				{
					return !SceneHelper.IsSceneRankless;
				}
				return false;
			}
		}

		public static LevelInfo CurrentLevelInfo
		{
			get
			{
				if (SceneHelper.CurrentScene == "Level 0-S")
				{
					return secretMissionInfos[0];
				}
				if (SceneHelper.CurrentScene == "Level 1-S")
				{
					return secretMissionInfos[1];
				}
				if (SceneHelper.CurrentScene == "Level 2-S")
				{
					return secretMissionInfos[2];
				}
				if (SceneHelper.CurrentScene == "Level 4-S")
				{
					return secretMissionInfos[3];
				}
				if (SceneHelper.CurrentScene == "Level 5-S")
				{
					return secretMissionInfos[4];
				}
				if (SceneHelper.CurrentScene == "Level 7-S")
				{
					return secretMissionInfos[5];
				}
				if (CurrentLevelHasInfo)
				{
					return GetLevelInfo(SceneHelper.CurrentLevelNumber);
				}
				return null;
			}
		}

		public static bool CurrentLevelHasSkulls
		{
			get
			{
				LevelInfo currentLevelInfo = CurrentLevelInfo;
				if (currentLevelInfo != null && currentLevelInfo.Skulls > SkullsType.None)
				{
					return data.randomizeSkulls;
				}
				return false;
			}
		}

		public static bool CurrentLevelHasSwitches
		{
			get
			{
				LevelInfo currentLevelInfo = CurrentLevelInfo;
				if (currentLevelInfo == null || currentLevelInfo.Id != 9 || !data.l1switch)
				{
					LevelInfo currentLevelInfo2 = CurrentLevelInfo;
					if (currentLevelInfo2 != null && currentLevelInfo2.Id == 27)
					{
						return data.l7switch;
					}
					return false;
				}
				return true;
			}
		}

		public static LevelInfo GetLevelInfo(int id)
		{
			foreach (LevelInfo levelInfo in levelInfos)
			{
				if (levelInfo.Id == id)
				{
					return levelInfo;
				}
			}
			Logger.LogWarning((object)$"No level info for ID {id}.");
			return null;
		}

		public static LevelInfo GetLevelInfo(string name)
		{
			foreach (LevelInfo levelInfo in levelInfos)
			{
				if (levelInfo.Name == name)
				{
					return levelInfo;
				}
			}
			Logger.LogWarning((object)("No level info for name " + name + "."));
			return null;
		}

		public static int GetLevelIdFromName(string name)
		{
			LevelInfo levelInfo = GetLevelInfo(name);
			if (levelInfo == null)
			{
				Logger.LogWarning((object)("No level info for name " + name + "."));
				return 0;
			}
			return levelInfo.Id;
		}

		public static string GetLevelNameFromId(int id)
		{
			LevelInfo levelInfo = GetLevelInfo(id);
			if (levelInfo == null)
			{
				Logger.LogWarning((object)$"No level info for ID {id}.");
				return null;
			}
			return levelInfo.Name;
		}

		public void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			new Harmony("archipelago").PatchAll();
			workingPath = Assembly.GetExecutingAssembly().Location;
			workingDir = Path.GetDirectoryName(workingPath);
			ConfigManager.Initialize();
			SceneManager.sceneLoaded += OnSceneLoaded;
			LocationManager.RegenerateItemDefinitions();
			AsyncOperationHandle<Sprite> val = Addressables.LoadAssetAsync<Sprite>((object)"Assets/Textures/UI/Controls/Round_VertHandle_Invert 1.png");
			UIManager.menuSprite1 = val.WaitForCompletion();
			Addressables.Release<Sprite>(val);
			AsyncOperationHandle<Sprite> val2 = Addressables.LoadAssetAsync<Sprite>((object)"Assets/Textures/UI/Controls/Round_BorderLarge.png");
			UIManager.menuSprite2 = val2.WaitForCompletion();
			Addressables.Release<Sprite>(val2);
			AsyncOperationHandle<TMP_FontAsset> val3 = Addressables.LoadAssetAsync<TMP_FontAsset>((object)"Assets/Fonts/Terminal/fs-tahoma-8px-v2 SDF.asset");
			UIManager.fontSecondary = val3.WaitForCompletion();
			Addressables.Release<TMP_FontAsset>(val3);
		}

		public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			if (SceneHelper.CurrentScene == "Intro" || SceneHelper.CurrentScene == "Bootstrap" || SceneHelper.CurrentScene == null)
			{
				return;
			}
			if ((Object)(object)obj == (Object)null)
			{
				obj = new GameObject
				{
					name = "Archipelago"
				};
				Object.DontDestroyOnLoad((Object)(object)obj);
				obj.transform.localPosition = new Vector3(960f, 540f, 0f);
				uim = obj.AddComponent<UIManager>();
				mw = obj.AddComponent<Multiworld>();
			}
			((MonoBehaviour)uim).StopCoroutine("DisplayMessage");
			UIManager.displayingMessage = false;
			UIManager.levels.Clear();
			UIManager.secrets.Clear();
			UIManager.createdSkullIcons = false;
			UIManager.createdSwitchIcons = false;
			uim.deathLinkMessage = null;
			Multiworld.DeathLinkManager?.RemoveQueuedDeathLink();
			LevelManager.skulls.Clear();
			ConfigManager.connectionInfo.text = "";
			if (ConfigManager.uiColorRandomizer.value == ColorOptions.EveryLoad)
			{
				ColorRandomizer.RandomizeUIColors();
			}
			if (ConfigManager.gunColorRandomizer.value == ColorOptions.EveryLoad)
			{
				ColorRandomizer.RandomizeGunColors();
			}
			if (SceneHelper.CurrentScene == "Main Menu")
			{
				bool flag = DataExists();
				UIManager.FindMenuObjects();
				mw.SetupServerCheckBlocker();
				if (flag && GameProgressSaver.GetTutorial() && !firstTimeLoad)
				{
					LoadData();
					ConfigManager.LoadConnectionInfo();
					ConfigManager.LoadStats();
					firstTimeLoad = true;
				}
				else if (!flag)
				{
					ConfigManager.ResetStatsDefaults();
				}
				UIManager.CreateMenuUI();
				if (flag && Multiworld.Authenticated)
				{
					((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Green;
				}
				else if (flag && !Multiworld.Authenticated)
				{
					((Graphic)UIManager.menuIcon.GetComponent<Image>()).color = Colors.Red;
				}
				if ((Object)(object)UIManager.log == (Object)null)
				{
					uim.CreateLogObject();
				}
				if (flag && data.randomizeSkulls)
				{
					UIManager.CreateMenuSkullIcons();
				}
				if (flag && (data.l1switch || data.l7switch))
				{
					UIManager.CreateMenuSwitchIcons();
				}
				if (data.completedLevels.Count >= data.goalRequirement)
				{
					if (data.goal.Contains("-S"))
					{
						GameProgressSaver.FoundSecretMission(int.Parse(data.goal.Substring(0, 1)));
					}
					else if (!data.unlockedLevels.Contains(data.goal))
					{
						data.unlockedLevels.Add(data.goal);
					}
				}
			}
			else if (IsInLevel && DataExists())
			{
				UIManager.CreateMessageUI();
			}
			else if (SceneHelper.CurrentScene == "Endless" && Multiworld.HintMode)
			{
				UIManager.CreateMessageUI();
			}
			if (!IsInIntro)
			{
				((Component)MonoSingleton<OptionsManager>.Instance.optionsMenu).gameObject.AddComponent<OptionsMenuState>();
			}
			if (DataExists() && (Object)(object)UIManager.log != (Object)null)
			{
				UIManager.AdjustLogBounds();
			}
			if (DataExists() && SceneHelper.CurrentScene == "Level 0-1")
			{
				LevelManager.ChangeIntro();
			}
			else if (DataExists() && SceneHelper.CurrentScene == "Level 1-2" && GameProgressSaver.GetGeneralProgress().nai0 == 0)
			{
				LevelManager.DeactivateNailgun();
			}
			else if (DataExists() && (SceneHelper.CurrentScene == "Level 1-4" || SceneHelper.CurrentScene == "Level 5-3") && data.hankRewards)
			{
				LevelManager.FindHank();
			}
			else if (DataExists() && SceneHelper.CurrentScene == "CreditsMuseum2")
			{
				LevelManager.FindRocketRaceButton();
			}
		}

		public static bool DataExists()
		{
			return File.Exists(Path.Combine(GameProgressSaver.BaseSavePath, $"Slot{GameProgressSaver.currentSlot + 1}") + "\\archipelago.json");
		}

		public static bool DataExists(int slotId)
		{
			return File.Exists(Path.Combine(GameProgressSaver.BaseSavePath, $"Slot{slotId}") + "\\archipelago.json");
		}

		public static void SaveData()
		{
			string path = Path.Combine(GameProgressSaver.BaseSavePath, $"Slot{GameProgressSaver.currentSlot + 1}") + "\\archipelago.json";
			byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject((object)data));
			File.WriteAllBytes(path, bytes);
		}

		public static void LoadData()
		{
			string path = Path.Combine(GameProgressSaver.BaseSavePath, $"Slot{GameProgressSaver.currentSlot + 1}") + "\\archipelago.json";
			if (File.Exists(path))
			{
				using (StreamReader streamReader = new StreamReader(path))
				{
					data = JsonConvert.DeserializeObject<Data>(streamReader.ReadToEnd());
				}
				Logger.LogInfo((object)("Loaded Archipelago data for slot " + (GameProgressSaver.currentSlot + 1) + "."));
				LocationManager.RegenerateItemDefinitions();
			}
			else
			{
				Logger.LogError((object)("Archipelago data for slot " + (GameProgressSaver.currentSlot + 1) + " does not exist."));
			}
		}

		public static void DeleteData(int slot)
		{
			string path = Path.Combine(GameProgressSaver.BaseSavePath, $"Slot{slot + 1}") + "\\archipelago.json";
			if (File.Exists(path))
			{
				File.Delete(path);
			}
		}

		public static void LockAllWeapons()
		{
			GameProgressMoneyAndGear obj = (LocationManager.generalProgress = GameProgressSaver.GetGeneralProgress());
			obj.rev0 = 0;
			obj.rev1 = 0;
			obj.rev2 = 0;
			obj.sho0 = 0;
			obj.sho1 = 0;
			obj.sho2 = 0;
			obj.nai0 = 0;
			obj.nai1 = 0;
			obj.nai2 = 0;
			obj.rock0 = 0;
			obj.rock1 = 0;
			obj.rock2 = 0;
			SaveGeneralProgress(obj);
		}

		public static void SaveGeneralProgress(GameProgressMoneyAndGear progress)
		{
			Traverse val = Traverse.Create(typeof(GameProgressSaver));
			val.Method("WriteFile", new object[2]
			{
				val.Property<string>("generalProgressPath", (object[])null).Value,
				progress
			}).GetValue();
		}

		public static bool IsFire2Unlocked(string weapon)
		{
			if (data.randomizeFire2 == Fire2Options.Disabled)
			{
				return true;
			}
			return data.unlockedFire2.Contains(weapon);
		}

		public static bool CanBreakGlass()
		{
			GameProgressMoneyAndGear generalProgress = GameProgressSaver.GetGeneralProgress();
			if (generalProgress.rev0 > 0)
			{
				if (data.revForm == WeaponForm.Standard && IsFire2Unlocked("rev0"))
				{
					return true;
				}
				if (data.revForm == WeaponForm.Alternate)
				{
					return true;
				}
			}
			if (generalProgress.rev1 > 0)
			{
				if (data.revForm == WeaponForm.Standard && IsFire2Unlocked("rev1"))
				{
					return true;
				}
				if (data.revForm == WeaponForm.Alternate)
				{
					return true;
				}
			}
			if (generalProgress.rev2 > 0)
			{
				if (data.revForm == WeaponForm.Standard && IsFire2Unlocked("rev2"))
				{
					return true;
				}
				if (data.revForm == WeaponForm.Alternate)
				{
					return true;
				}
			}
			if (generalProgress.sho0 > 0)
			{
				if (data.shoForm == WeaponForm.Standard && IsFire2Unlocked("sho0"))
				{
					return true;
				}
				if (data.shoForm == WeaponForm.Alternate)
				{
					return true;
				}
			}
			if (generalProgress.sho1 > 0)
			{
				if (data.shoForm == WeaponForm.Standard && IsFire2Unlocked("sho1"))
				{
					return true;
				}
				if (data.shoForm == WeaponForm.Alternate)
				{
					return true;
				}
			}
			if (generalProgress.sho2 > 0 && data.shoForm == WeaponForm.Alternate)
			{
				return true;
			}
			if (generalProgress.rai0 > 0)
			{
				return true;
			}
			if (generalProgress.rai2 > 0)
			{
				return true;
			}
			if (generalProgress.rock0 > 0)
			{
				return true;
			}
			if (generalProgress.rock1 > 0)
			{
				return true;
			}
			if (generalProgress.rock2 > 0)
			{
				return true;
			}
			if (generalProgress.arm1 > 0)
			{
				return true;
			}
			return false;
		}

		public static List<string> SearchAssetKeys(string contains)
		{
			List<string> list = new List<string>();
			foreach (IResourceLocator resourceLocator in Addressables.ResourceLocators)
			{
				if (!(resourceLocator is ResourceLocationMap))
				{
					continue;
				}
				foreach (string key in resourceLocator.Keys)
				{
					if (key.Contains(contains))
					{
						list.Add(key);
					}
				}
			}
			return list;
		}

		public static List<T> FindAllComponentsInCurrentScene<T>() where T : Behaviour
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			List<T> list = new List<T>();
			T[] array = Resources.FindObjectsOfTypeAll<T>();
			foreach (T val in array)
			{
				Scene val2 = ((Component)(object)val).gameObject.scene;
				string name = ((Scene)(ref val2)).name;
				val2 = SceneManager.GetActiveScene();
				if (name == ((Scene)(ref val2)).name)
				{
					list.Add(val);
				}
			}
			return list;
		}

		public static void ValidateArms()
		{
			bool flag = false;
			bool flag2 = GameProgressSaver.CheckGear("arm1") == 1;
			if (flag2 && !data.hasArm && MonoSingleton<PrefsManager>.Instance.GetInt("weapon.arm0", 0) == 1)
			{
				MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 0);
				flag = true;
			}
			if (MonoSingleton<PrefsManager>.Instance.GetInt("weapon.arm0", 0) == 0 && MonoSingleton<PrefsManager>.Instance.GetInt("weapon.arm1", 0) == 0)
			{
				if (flag2)
				{
					MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm1", 1);
				}
				else
				{
					MonoSingleton<PrefsManager>.Instance.SetInt("weapon.arm0", 1);
				}
				flag = true;
			}
			if (flag)
			{
				MonoSingleton<FistControl>.Instance.ResetFists();
			}
		}

		[IteratorStateMachine(typeof(<ApplyLoadout>d__65))]
		public IEnumerator ApplyLoadout(WeaponLoadout loadout)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ApplyLoadout>d__65(0)
			{
				loadout = loadout
			};
		}
	}
	public class Data
	{
		public string seed = string.Empty;

		public string version = string.Empty;

		public string serverVersion = string.Empty;

		public long index;

		public string host_name;

		public string slot_name;

		public string password;

		public HashSet<string> @checked = new HashSet<string>();

		public int playerCount = 1;

		public List<RecentLocation> recentLocations = new List<RecentLocation>();

		public HashSet<string> unlockedLevels = new HashSet<string>();

		public HashSet<string> unlockedSecrets = new HashSet<string>();

		public HashSet<string> completedLevels = new HashSet<string>();

		public HashSet<string> purchasedItems = new HashSet<string>();

		public string start = "0-1";

		public string goal = "6-2";

		public int goalRequirement = 20;

		public bool perfectGoal;

		public EnemyOptions enemyRewards;

		public bool challengeRewards;

		public bool pRankRewards;

		public bool hankRewards;

		public bool clashReward;

		public bool fishRewards;

		public bool cleanRewards;

		public bool chessReward;

		public bool rocketReward;

		public bool hasArm = true;

		public int dashes = 3;

		public int walljumps = 3;

		public bool canSlide = true;

		public bool canSlam = true;

		public int multiplier = 1;

		public WeaponForm revForm;

		public bool revstd = true;

		public bool revalt;

		public WeaponForm shoForm;

		public bool shostd = true;

		public bool shoalt;

		public WeaponForm naiForm;

		public bool naistd = true;

		public bool naialt;

		public Fire2Options randomizeFire2;

		public HashSet<string> unlockedFire2 = new HashSet<string>();

		public bool randomizeSkulls;

		public HashSet<string> unlockedSkulls = new HashSet<string>();

		public int unlockedSkulls1_4;

		public int unlockedSkulls5_1;

		public bool l1switch;

		public bool l7switch;

		public bool[] limboSwitches = new bool[4];

		public bool[] shotgunSwitches = new bool[3];

		public bool musicRandomizer;

		public Dictionary<string, string> music = new Dictionary<string, string>();

		public bool cybergrindHints = true;

		public bool deathLink;

		public override string ToString()
		{
			if (!Utility.IsNullOrWhiteSpace(slot_name))
			{
				if (@checked.Count != 1)
				{
					return $"Slot {GameProgressSaver.currentSlot + 1} | {slot_name} | {@checked.Count} locations checked.";
				}
				return $"Slot {GameProgressSaver.currentSlot + 1} | {slot_name} | {@checked.Count} location checked.";
			}
			return "No data for current slot.";
		}
	}
	public static class LevelManager
	{
		public static Dictionary<string, GameObject> skulls = new Dictionary<string, GameObject>();

		public static Door redDoor;

		public static void FindSkulls()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_0038: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Invalid comparison between Unknown and I4
			//IL_00e3: Unknown result type (might be due to invalid IL o