Decompiled source of CrashoutCrewArchipelagoClient v1.0.4

AggroButtonSetting.dll

Decompiled 18 minutes ago
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using Aggro.Core;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
public sealed class ButtonSetting : AggroSettingBase
{
	private Action _onPressed;

	private string _buttonLabel;

	public Action GetOnPressed()
	{
		return _onPressed;
	}

	public string GetButtonLabel()
	{
		return _buttonLabel;
	}

	public void SetButtonLabel(string buttonLabel)
	{
		_buttonLabel = buttonLabel;
	}

	public ButtonSetting(string buttonLabel, Action onPressed)
	{
		_onPressed = onPressed;
		_buttonLabel = buttonLabel;
	}

	public override void SetToDefault()
	{
	}

	protected override void SaveToPrefs(string preferencesKey)
	{
	}

	protected override void LoadFromPrefs(string preferencesKey)
	{
	}
}
public class ButtonSettingUI : AggroSettingUI
{
	private ButtonSetting _setting;

	public TextMeshProUGUI buttonLabel;

	public override void Set(AggroSettingBase setting)
	{
		if (setting is ButtonSetting setting2)
		{
			_setting = setting2;
			((AggroSettingUI)this).Refresh();
		}
		else
		{
			Debug.LogWarning((object)"[SETTINGS] Invalid setting type for ButtonSettingUI!");
		}
	}

	public override void Refresh()
	{
		((TMP_Text)buttonLabel).text = LocalizedText.GetText(_setting.GetButtonLabel(), true);
	}

	public void OnPressed()
	{
		_setting.GetOnPressed()?.Invoke();
	}
}
[CompilerGenerated]
[EditorBrowsable(EditorBrowsableState.Never)]
[GeneratedCode("Unity.MonoScriptGenerator.MonoScriptInfoGenerator", null)]
internal class UnitySourceGeneratedAssemblyMonoScriptTypes_v1
{
	private struct MonoScriptData
	{
		public byte[] FilePathsData;

		public byte[] TypesData;

		public int TotalTypes;

		public int TotalFiles;

		public bool IsEditorOnly;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	private static MonoScriptData Get()
	{
		return new MonoScriptData
		{
			FilePathsData = new byte[146]
			{
				0, 0, 0, 1, 0, 0, 0, 64, 92, 65,
				115, 115, 101, 116, 115, 92, 67, 117, 115, 116,
				111, 109, 92, 66, 117, 116, 116, 111, 110, 83,
				101, 116, 116, 105, 110, 103, 92, 65, 103, 103,
				114, 111, 66, 117, 116, 116, 111, 110, 83, 101,
				116, 116, 105, 110, 103, 92, 66, 117, 116, 116,
				111, 110, 83, 101, 116, 116, 105, 110, 103, 46,
				99, 115, 0, 0, 0, 1, 0, 0, 0, 66,
				92, 65, 115, 115, 101, 116, 115, 92, 67, 117,
				115, 116, 111, 109, 92, 66, 117, 116, 116, 111,
				110, 83, 101, 116, 116, 105, 110, 103, 92, 65,
				103, 103, 114, 111, 66, 117, 116, 116, 111, 110,
				83, 101, 116, 116, 105, 110, 103, 92, 66, 117,
				116, 116, 111, 110, 83, 101, 116, 116, 105, 110,
				103, 85, 73, 46, 99, 115
			},
			TypesData = new byte[40]
			{
				0, 0, 0, 0, 14, 124, 66, 117, 116, 116,
				111, 110, 83, 101, 116, 116, 105, 110, 103, 0,
				0, 0, 0, 16, 124, 66, 117, 116, 116, 111,
				110, 83, 101, 116, 116, 105, 110, 103, 85, 73
			},
			TotalFiles = 2,
			TotalTypes = 2,
			IsEditorOnly = false
		};
	}
}

AggroTextSetting.dll

Decompiled 18 minutes ago
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using Aggro.Core;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
public sealed class TextSetting : AggroSettingBase
{
	private Action<string> _onSaved;

	public string defaultText { get; private set; }

	public string text { get; private set; }

	public bool isPassword { get; private set; }

	public TextSetting(string defaultText, string text, bool isPassword)
	{
		this.defaultText = defaultText;
		this.text = text;
		this.isPassword = isPassword;
	}

	public override void SetToDefault()
	{
		text = defaultText;
	}

	public void SetText(string newText)
	{
		text = newText;
	}

	protected override void SaveToPrefs(string preferencesKey)
	{
		PlayerPrefs.SetString(preferencesKey, text);
		_onSaved?.Invoke(text);
	}

	protected override void LoadFromPrefs(string preferencesKey)
	{
		text = PlayerPrefs.GetString(preferencesKey, defaultText);
	}
}
public class TextSettingUI : AggroSettingUI
{
	public TMP_InputField _text;

	private TextSetting _setting;

	public override void Set(AggroSettingBase setting)
	{
		if (setting is TextSetting setting2)
		{
			_setting = setting2;
			((AggroSettingUI)this).Refresh();
		}
		else
		{
			Debug.LogWarning((object)"[SETTINGS] Invalid setting type for TextSettingUI!");
		}
	}

	public override void Refresh()
	{
		_text.text = _setting.text;
		Graphic placeholder = _text.placeholder;
		TMP_Text val = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null);
		if ((Object)(object)val != (Object)null)
		{
			val.text = _setting.defaultText;
		}
		if (_setting.isPassword)
		{
			_text.contentType = (ContentType)7;
		}
	}

	public void OnEndEdit()
	{
		_setting.SetText(_text.text);
		((AggroSettingBase)_setting).Save();
	}
}
[CompilerGenerated]
[EditorBrowsable(EditorBrowsableState.Never)]
[GeneratedCode("Unity.MonoScriptGenerator.MonoScriptInfoGenerator", null)]
internal class UnitySourceGeneratedAssemblyMonoScriptTypes_v1
{
	private struct MonoScriptData
	{
		public byte[] FilePathsData;

		public byte[] TypesData;

		public int TotalTypes;

		public int TotalFiles;

		public bool IsEditorOnly;
	}

	[MethodImpl(MethodImplOptions.AggressiveInlining)]
	private static MonoScriptData Get()
	{
		return new MonoScriptData
		{
			FilePathsData = new byte[134]
			{
				0, 0, 0, 1, 0, 0, 0, 58, 92, 65,
				115, 115, 101, 116, 115, 92, 67, 117, 115, 116,
				111, 109, 92, 84, 101, 120, 116, 83, 101, 116,
				116, 105, 110, 103, 92, 65, 103, 103, 114, 111,
				84, 101, 120, 116, 83, 101, 116, 116, 105, 110,
				103, 92, 84, 101, 120, 116, 83, 101, 116, 116,
				105, 110, 103, 46, 99, 115, 0, 0, 0, 1,
				0, 0, 0, 60, 92, 65, 115, 115, 101, 116,
				115, 92, 67, 117, 115, 116, 111, 109, 92, 84,
				101, 120, 116, 83, 101, 116, 116, 105, 110, 103,
				92, 65, 103, 103, 114, 111, 84, 101, 120, 116,
				83, 101, 116, 116, 105, 110, 103, 92, 84, 101,
				120, 116, 83, 101, 116, 116, 105, 110, 103, 85,
				73, 46, 99, 115
			},
			TypesData = new byte[36]
			{
				0, 0, 0, 0, 12, 124, 84, 101, 120, 116,
				83, 101, 116, 116, 105, 110, 103, 0, 0, 0,
				0, 14, 124, 84, 101, 120, 116, 83, 101, 116,
				116, 105, 110, 103, 85, 73
			},
			TotalFiles = 2,
			TotalTypes = 2,
			IsEditorOnly = false
		};
	}
}

Archipelago.Multiclient.Net.dll

Decompiled 18 minutes ago
#define DEBUG
using System;
using System.Collections;
using System.Collections.Concurrent;
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.Linq.Expressions;
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.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
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 Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.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 © 2026")]
[assembly: AssemblyDescription("A client library for use with .NET based prog-langs for interfacing with Archipelago hosts.")]
[assembly: AssemblyFileVersion("6.7.1.0")]
[assembly: AssemblyInformationalVersion("6.7.1+0c57591db30f2497b0b4fef87164aa2bbe2e51b2")]
[assembly: AssemblyProduct("Archipelago.MultiClient.Net")]
[assembly: AssemblyTitle("Archipelago.MultiClient.Net")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ArchipelagoMW/Archipelago.MultiClient.Net")]
[assembly: AssemblyVersion("6.7.1.0")]
internal interface IConcurrentHashSet<T>
{
	bool TryAdd(T item);

	bool Contains(T item);

	void UnionWith(T[] otherSet);

	T[] ToArray();

	ReadOnlyCollection<T> AsToReadOnlyCollection();

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

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

	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
	{
		try
		{
			return base.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, 1);
		}

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

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

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

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

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

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

		public static DataStorageElement operator +(DataStorageElement a, string b)
		{
			return new DataStorageElement(a, OperationType.Add, 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, JArray.FromObject(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, b);
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public static implicit operator DataStorageElement(string s)
		{
			if (s != null)
			{
				return new DataStorageElement(OperationType.Replace, s);
			}
			return new DataStorageElement(OperationType.Replace, 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, JArray.FromObject(a));
		}

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

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

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

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

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

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

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

		public static implicit operator DataStorageElement(List<object> l)
		{
			return new DataStorageElement(OperationType.Replace, JArray.FromObject(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(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(e.Context.GetData(e.Context.Key).ToString(), out result2) ? new BigInteger?(result2) : ((BigInteger?)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(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, JArray.FromObject(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)
		{
			if (e.cachedValue != null)
			{
				return ((JArray)e.cachedValue).ToObject<T>();
			}
			JArray jArray = e.Context.GetData(e.Context.Key).ToObject<JArray>() ?? new JArray();
			foreach (OperationSpecification operation in e.Operations)
			{
				switch (operation.OperationType)
				{
				case OperationType.Add:
					if (operation.Value.Type != JTokenType.Array)
					{
						throw new InvalidOperationException($"Cannot perform operation {OperationType.Add} on Array value, with a non Array value: {operation.Value}");
					}
					jArray.Merge(operation.Value);
					break;
				case OperationType.Replace:
					if (operation.Value.Type != JTokenType.Array)
					{
						throw new InvalidOperationException($"Cannot replace Array value, with a non Array value: {operation.Value}");
					}
					jArray = operation.Value.ToObject<JArray>() ?? new JArray();
					break;
				default:
					throw new InvalidOperationException($"Cannot perform operation {operation.OperationType} on Array value");
				}
			}
			e.cachedValue = jArray;
			return jArray.ToObject<T>();
		}

		private static string RetrieveAndReturnStringValue(DataStorageElement e)
		{
			if (e.cachedValue != null)
			{
				return (string?)e.cachedValue;
			}
			JToken jToken = e.Context.GetData(e.Context.Key);
			string text = ((jToken.Type == JTokenType.Null) ? null : jToken.ToString());
			foreach (OperationSpecification operation in e.Operations)
			{
				switch (operation.OperationType)
				{
				case OperationType.Add:
					text += (string?)operation.Value;
					break;
				case OperationType.Mul:
					if (operation.Value.Type != JTokenType.Integer)
					{
						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 = JValue.CreateNull();
			}
			else
			{
				e.cachedValue = 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 = 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 = 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 = i
			};
		}

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

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

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

		public static OperationSpecification Min(decimal i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Min,
				Value = 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 = i
			};
		}

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

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

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

		public static OperationSpecification Max(decimal i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.Max,
				Value = 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 = 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 = JObject.FromObject(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 = 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 = 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 = 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 = i
			};
		}

		public static OperationSpecification RightShift(long i)
		{
			return new OperationSpecification
			{
				OperationType = OperationType.RightShift,
				Value = 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)
		{
			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 settings = new JsonSerializerSettings
			{
				NullValueHandling = NullValueHandling.Ignore,
				Formatting = Newtonsoft.Json.Formatting.None
			};
			return JsonConvert.SerializeObject(minimalSerializableItemInfo, settings);
		}

		public static SerializableItemInfo FromJson(string json, IArchipelagoSession session = null)
		{
			ItemInfoStreamingContext additional = ((session != null) ? new ItemInfoStreamingContext
			{
				Items = session.Items,
				Locations = session.Locations,
				PlayerHelper = session.Players,
				ConnectionInfo = session.ConnectionInfo
			} : null);
			JsonSerializerSettings settings = new JsonSerializerSettings
			{
				Context = new StreamingContext(StreamingContextStates.Other, additional)
			};
			return JsonConvert.DeserializeObject<SerializableItemInfo>(json, settings);
		}

		[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(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, 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)
		{
			if (!(packet is RetrievedPacket retrievedPacket))
			{
				if (packet is SetReplyPacket setReplyPacket)
				{
					if (setReplyPacket.AdditionalArguments != null && setReplyPacket.AdditionalArguments.ContainsKey("Reference") && setReplyPacket.AdditionalArguments["Reference"].Type == JTokenType.String && ((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, 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"] = 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>());
			};
			if (retrieveCurrentClientStatus)
			{
				GetClientStatusAsync(slot, team).ContinueWith(delegate(Task<ArchipelagoClientState> t)
				{
					onStatusUpdated(t.Result);
				});
			}
		}

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

		public Task<bool> GetRaceModeAsync()
		{
			return GetRaceModeElement().GetAsync<int?>().ContinueWith((Task<int?> t) => t.Result.GetValueOrDefault() > 0);
		}
	}
	public interface IDataStorageWrapper
	{
		Hint[] GetHints(int? slot = null, int? team = null);

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

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

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

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

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

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

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

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

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

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

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

		Task<ArchipelagoClientState> GetClientStatusAsync(int? slot = null, int? team = null);

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

		bool GetRaceMode();

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

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

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

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

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

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

		private readonly ILocationCheckHelper locationCheckHelper;

		private readonly IRoomStateHelper roomStateHelper;

		private readonly IPlayerHelper players;

		private readonly IDataStorageHelper dataStorageHelper;

		int

CrashoutCrew_APClient.dll

Decompiled 18 minutes ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Aggro.Core;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.Converters;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.MessageLog.Messages;
using Archipelago.MultiClient.Net.MessageLog.Parts;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using BepInEx;
using BepInEx.Logging;
using CrashoutCrew_APClient.Patches;
using CrashoutCrew_LobbyEnforcer;
using CrashoutCrew_SkysTheLimit;
using FMODUnity;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("aggro.core")]
[assembly: IgnoresAccessChecksTo("febjam")]
[assembly: AssemblyCompany("CrashoutCrew_APClient")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+31a39948addc7464f2936539789d70ab6d2b2486")]
[assembly: AssemblyProduct("CrashoutCrew_APClient")]
[assembly: AssemblyTitle("CrashoutCrew_APClient")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[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]
	[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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TemplatePlugin
{
	internal static class TemplatePluginInfo
	{
		public const string PLUGIN_GUID = "crashout_crew_ap_client";

		public const string PLUGIN_NAME = "CrashoutCrew_APClient";

		public const string GAME_NAME = "CrashoutCrew";
	}
}
namespace CrashoutCrew_APClient
{
	public class APConsole : MonoBehaviour
	{
		private enum ConsoleAnchorCorner
		{
			BottomLeft,
			BottomRight,
			TopLeft,
			TopRight
		}

		[Serializable]
		public class LogEntry(string msg)
		{
			public enum State
			{
				SlideIn,
				Hold,
				FadeOut
			}

			public State state;

			public float stateTimer;

			public float offsetY;

			public float baseY;

			public float animatedY;

			public TextMeshProUGUI? text;

			public Image? background;

			public string message = msg;

			public string colorizedMessage = msg;

			public float height = 28f;
		}

		private static readonly Dictionary<string, string> KeywordColors = new Dictionary<string, string>
		{
			{ "Bell", "#C325FA" },
			{ "Shop", "#FFE552" },
			{ "Charge Pad", "#FF8C52" },
			{ "Lock In Protocol", "#F21F1F" },
			{ "Fire Extinguisher", "#F21F1F" },
			{ "Super Scrubber", "#72A5ED" },
			{ "Scrubbie", "#72A5ED" },
			{ "Standard Shelf", "#6FDE62" },
			{ "Small Fire Sprinkler", "#00B7FF" },
			{ "Sturdy Shelf", "#4252FF" },
			{ "Teleporter", "#00FFFB" },
			{ "Trash Compactor", "#D3E3E3" },
			{ "Vacuum Cleaner", "#FFDB00" },
			{ "Leaf Blower", "#00FF08" },
			{ "Giga Sprinkler", "#00B7FF" },
			{ "Water Balloon Pump", "#F21F1F" },
			{ "Wild Card Station", "#FF00E6" },
			{ "Nitro Canisters", "#FC8242" },
			{ "Aromatherapy", "#CE6CF0" },
			{ "Racing Tires", "#B2ACE8" },
			{ "Blast Shields", "#D3E3E3" },
			{ "Tire Chains", "#D3E3E3" },
			{ "Cup Holder", "#CE6CF0" },
			{ "Personal Fan", "#9EF0E1" },
			{ "The Grippers", "#F5EB1D" },
			{ "Sick-ass Spoiler", "#FFCD00" },
			{ "Speed Upgrade", "#9355F2" },
			{ "Strength Upgrade", "#9355F2" },
			{ "Boost Upgrade", "#9355F2" },
			{ "Stress Upgrade", "#9355F2" },
			{ "Random Cosmetic", "#E0C38D" },
			{ "Contract", "#ffffff" },
			{ "Shift", "#ffffff" },
			{ "Delivery", "#ffffff" }
		};

		private const string FontName = "ChelseaMarket-Regular SDF";

		private readonly Color _textColor = new Color(0.85f, 0.85f, 0.85f, 1f);

		private readonly Color _backColor = new Color(0f, 0f, 0f, 0.8f);

		private const int MaxHistoryEntries = 1000;

		private const KeyCode LogToggleKey = (KeyCode)288;

		private const KeyCode HistoryToggleKey = (KeyCode)289;

		private const CursorLockMode DefaultCursorMode = (CursorLockMode)1;

		private const bool DefaultCursorVisible = false;

		private const float DefaultMessageHeight = 28f;

		private const float DefaultConsoleHeight = 250f;

		private const float DefaultConsoleWidth = 600f;

		public float slideInTime = 0.25f;

		public float holdTime = 2.5f;

		public float fadeOutTime = 0.4f;

		private const float SlideInOffset = -50f;

		private const float FadeUpOffset = 20f;

		private const float PaddingX = 25f;

		private const float PaddingY = 25f;

		private const float MessageSpacing = 2f;

		private readonly ConsoleAnchorCorner AnchorCorner;

		private const float ConsoleWidth = 600f;

		private const float ConsoleHeight = 250f;

		private const float MessageHeight = 28f;

		private bool _rebuildHistoryDirty;

		private int _historyBuiltCount;

		private static TMP_FontAsset? _font;

		private readonly ConcurrentQueue<Image> _backgroundPool = new ConcurrentQueue<Image>();

		private ConcurrentQueue<LogEntry> _cachedEntries = new ConcurrentQueue<LogEntry>();

		private readonly ConcurrentQueue<TextMeshProUGUI> _textPool = new ConcurrentQueue<TextMeshProUGUI>();

		private readonly List<LogEntry> _visibleEntries = new List<LogEntry>();

		private readonly List<LogEntry> _historyEntries = new List<LogEntry>();

		private GameObject? _historyPanel;

		private RectTransform? _historyContent;

		private bool _showHistory;

		private ScrollRect? _historyScrollRect;

		private RectTransform? _historyViewport;

		private Transform? _messageParent;

		private bool _showConsole = true;

		private static APConsole? _instance;

		public static APConsole Instance
		{
			get
			{
				if ((Object)(object)_instance == (Object)null)
				{
					Create();
				}
				return _instance;
			}
		}

		private static void Create()
		{
			//IL_0041: 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_004c: Expected O, but got Unknown
			if ((Object)(object)_instance != (Object)null)
			{
				return;
			}
			_font = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset x) => ((Object)x).name == "ChelseaMarket-Regular SDF"));
			GameObject val = new GameObject("ArchipelagoConsoleUI");
			Object.DontDestroyOnLoad((Object)val);
			_instance = val.AddComponent<APConsole>();
			_instance.BuildUI();
			_instance.slideInTime = PluginMain.MessageInTime;
			_instance.holdTime = PluginMain.MessageHoldTime;
			_instance.fadeOutTime = PluginMain.MessageOutTime;
			_instance.Log("Welcome to Crashout Crew Archipelago!");
			_instance.Log("by xMcacutt");
			_instance.Log($"Press {(object)(KeyCode)288} to Toggle log & {(object)(KeyCode)289} to toggle history");
			_instance.DebugLog("Colour Test");
			foreach (string key in KeywordColors.Keys)
			{
				_instance.DebugLog(key);
			}
		}

		private void Update()
		{
			UpdateMessages(Time.deltaTime);
			TryAddNewMessages();
			if (((ButtonControl)Keyboard.current.f7Key).wasPressedThisFrame)
			{
				ToggleConsole();
			}
			if (((ButtonControl)Keyboard.current.f8Key).wasPressedThisFrame)
			{
				ToggleHistory();
			}
			if (_showHistory)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
			if (_showHistory && _rebuildHistoryDirty)
			{
				_rebuildHistoryDirty = false;
				RebuildHistory();
			}
		}

		private void UpdateMessages(float delta)
		{
			for (int num = _visibleEntries.Count - 1; num >= 0; num--)
			{
				LogEntry entry = _visibleEntries[num];
				if (AnimateEntry(entry, delta))
				{
					RecycleEntry(entry);
					_visibleEntries.RemoveAt(num);
					RecalculateBaseY();
				}
				else
				{
					UpdateEntryVisual(entry);
				}
			}
		}

		private void RecalculateBaseY()
		{
			float num = 0f;
			for (int num2 = _visibleEntries.Count - 1; num2 >= 0; num2--)
			{
				LogEntry logEntry = _visibleEntries[num2];
				logEntry.baseY = num;
				num += logEntry.height + 2f;
			}
		}

		private bool AnimateEntry(LogEntry entry, float delta)
		{
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			entry.stateTimer += delta;
			switch (entry.state)
			{
			case LogEntry.State.SlideIn:
			{
				float num3 = Mathf.Clamp01(entry.stateTimer / slideInTime);
				entry.offsetY = Mathf.Lerp(-50f, 0f, EaseOutQuad(num3));
				if (num3 >= 1f)
				{
					entry.state = LogEntry.State.Hold;
					entry.stateTimer = 0f;
				}
				break;
			}
			case LogEntry.State.Hold:
				entry.offsetY = 0f;
				if (entry.stateTimer >= holdTime)
				{
					entry.state = LogEntry.State.FadeOut;
					entry.stateTimer = 0f;
				}
				break;
			case LogEntry.State.FadeOut:
			{
				float num = Mathf.Clamp01(entry.stateTimer / fadeOutTime);
				entry.offsetY = Mathf.Lerp(0f, 20f, num);
				float num2 = 1f - num;
				if ((Object)(object)entry.text != (Object)null)
				{
					((Graphic)entry.text).color = new Color(_textColor.r, _textColor.g, _textColor.b, num2);
				}
				if ((Object)(object)entry.background != (Object)null)
				{
					((Graphic)entry.background).color = new Color(_backColor.r, _backColor.g, _backColor.b, num2);
				}
				if (num >= 1f)
				{
					return true;
				}
				break;
			}
			}
			return false;
		}

		private static float EaseOutQuad(float x)
		{
			return 1f - (1f - x) * (1f - x);
		}

		private void TryAddNewMessages()
		{
			if (_showHistory || !_cachedEntries.Any())
			{
				return;
			}
			int num = Mathf.FloorToInt(8.928572f);
			if (_visibleEntries.Count < num)
			{
				_cachedEntries.TryDequeue(out LogEntry result);
				if (result != null)
				{
					result.state = LogEntry.State.SlideIn;
					result.stateTimer = 0f;
					result.offsetY = -50f;
					result.animatedY = result.baseY + result.offsetY;
					CreateEntryVisual(result);
					_visibleEntries.Add(result);
					RecalculateBaseY();
					result.animatedY = result.baseY + result.offsetY;
				}
			}
		}

		private void ApplyRectSettings(RectTransform rt, Vector2 min, Vector2 max, Vector2 pivot, Vector2 pos, Vector2 size)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			rt.anchorMin = min;
			rt.anchorMax = max;
			rt.pivot = pivot;
			rt.anchoredPosition = pos;
			rt.sizeDelta = size;
		}

		private void PositionMessageContainer(RectTransform rect)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			Vector2 min;
			Vector2 val2 = default(Vector2);
			Vector2 pos = default(Vector2);
			switch (AnchorCorner)
			{
			case ConsoleAnchorCorner.BottomLeft:
				((Vector2)(ref val))..ctor(0f, 0f);
				min = (val2 = val);
				((Vector2)(ref pos))..ctor(25f, 25f);
				break;
			case ConsoleAnchorCorner.BottomRight:
				((Vector2)(ref val2))..ctor(1f, 0f);
				min = val2;
				((Vector2)(ref val))..ctor(1f, 0f);
				((Vector2)(ref pos))..ctor(-25f, 25f);
				break;
			case ConsoleAnchorCorner.TopLeft:
				((Vector2)(ref val2))..ctor(0f, 1f);
				min = val2;
				((Vector2)(ref val))..ctor(0f, 1f);
				((Vector2)(ref pos))..ctor(25f, -25f);
				break;
			case ConsoleAnchorCorner.TopRight:
				((Vector2)(ref val2))..ctor(1f, 1f);
				min = val2;
				((Vector2)(ref val))..ctor(1f, 1f);
				((Vector2)(ref pos))..ctor(-25f, -25f);
				break;
			default:
				((Vector2)(ref val))..ctor(0f, 0f);
				min = (val2 = val);
				((Vector2)(ref pos))..ctor(25f, 25f);
				break;
			}
			ApplyRectSettings(rect, min, val2, val, pos, new Vector2(600f, 250f));
		}

		private void PositionHistoryPanel(RectTransform rect)
		{
			PositionMessageContainer(rect);
		}

		private void AddHistoryEntryVisual(LogEntry entry)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			Image background = GetBackground();
			((Component)background).transform.SetParent((Transform)(object)_historyContent, false);
			RectTransform rectTransform = ((Graphic)background).rectTransform;
			ApplyRectSettings(rectTransform, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 1f), Vector2.zero, new Vector2(600f, 28f));
			TextMeshProUGUI text = GetText();
			RectTransform rectTransform2 = ((TMP_Text)text).rectTransform;
			((Transform)rectTransform2).SetParent(((Component)background).transform, false);
			rectTransform2.anchorMin = new Vector2(0f, 0f);
			rectTransform2.anchorMax = new Vector2(1f, 1f);
			rectTransform2.pivot = new Vector2(0f, 0.5f);
			rectTransform2.offsetMin = new Vector2(8f, 4f);
			rectTransform2.offsetMax = new Vector2(-8f, -4f);
			entry.text = text;
			entry.background = background;
			((Graphic)text).color = _textColor;
			((Graphic)background).color = _backColor;
			((TMP_Text)text).text = entry.msg;
			Canvas.ForceUpdateCanvases();
			LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform2);
			float preferredHeight = Mathf.Max(28f, ((TMP_Text)text).preferredHeight + 8f);
			(((Component)background).GetComponent<LayoutElement>() ?? ((Component)background).gameObject.AddComponent<LayoutElement>()).preferredHeight = preferredHeight;
		}

		private void CreateEntryVisual(LogEntry entry)
		{
			//IL_0022: 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_002c: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			Image background = GetBackground();
			((Component)background).transform.SetParent(_messageParent, false);
			RectTransform rectTransform = ((Graphic)background).rectTransform;
			ApplyRectSettings(rectTransform, Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero, new Vector2(600f, 28f));
			TextMeshProUGUI text = GetText();
			RectTransform rectTransform2 = ((TMP_Text)text).rectTransform;
			((Transform)rectTransform2).SetParent(((Component)background).transform, false);
			rectTransform2.anchorMin = new Vector2(0f, 0f);
			rectTransform2.anchorMax = new Vector2(1f, 1f);
			rectTransform2.pivot = new Vector2(0f, 0.5f);
			rectTransform2.offsetMin = new Vector2(8f, 4f);
			rectTransform2.offsetMax = new Vector2(-8f, -4f);
			entry.text = text;
			entry.background = background;
			((Graphic)text).color = _textColor;
			((Graphic)background).color = _backColor;
			UpdateEntryVisual(entry);
		}

		private void UpdateEntryVisual(LogEntry entry)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)entry.text != (Object)null)
			{
				((TMP_Text)entry.text).text = entry.msg;
				float preferredHeight = ((TMP_Text)entry.text).preferredHeight;
				entry.height = Mathf.Max(28f, preferredHeight + 8f);
				if ((Object)(object)entry.background != (Object)null)
				{
					((Graphic)entry.background).rectTransform.sizeDelta = new Vector2(600f, entry.height);
				}
			}
			float num = entry.baseY + entry.offsetY;
			entry.animatedY = Mathf.Lerp(entry.animatedY, num, Time.deltaTime * 12f);
			if ((Object)(object)entry.background != (Object)null)
			{
				((Graphic)entry.background).rectTransform.anchoredPosition = new Vector2(0f, entry.animatedY);
			}
		}

		private TextMeshProUGUI GetText()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			if (_textPool.TryDequeue(out TextMeshProUGUI result) && (Object)(object)result != (Object)null)
			{
				((Component)result).gameObject.SetActive(true);
				return result;
			}
			TextMeshProUGUI component = new GameObject("LogText", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(TextMeshProUGUI)
			}).GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).fontSize = 15f;
			((Graphic)component).color = _textColor;
			((TMP_Text)component).font = _font;
			((TMP_Text)component).wordSpacing = 20f;
			((TMP_Text)component).alignment = (TextAlignmentOptions)4097;
			return component;
		}

		private Image GetBackground()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (_backgroundPool.TryDequeue(out Image result) && (Object)(object)result != (Object)null)
			{
				((Component)result).gameObject.SetActive(true);
				return result;
			}
			Image obj = new GameObject("LogBG").AddComponent<Image>();
			((Graphic)obj).color = _backColor;
			obj.type = (Type)1;
			return obj;
		}

		private void RecycleEntry(LogEntry entry)
		{
			if ((Object)(object)entry.text != (Object)null)
			{
				((Component)entry.text).gameObject.SetActive(false);
				_textPool.Enqueue(entry.text);
				entry.text = null;
			}
			if ((Object)(object)entry.background != (Object)null)
			{
				((Component)entry.background).gameObject.SetActive(false);
				_backgroundPool.Enqueue(entry.background);
				entry.background = null;
			}
		}

		private string Colorize(string input)
		{
			if (string.IsNullOrEmpty(input))
			{
				return input;
			}
			List<string> list = Tokenize(input);
			ApplyMultiWordColoring(list);
			ApplySingleWordColoring(list);
			return string.Concat(list);
		}

		private List<string> Tokenize(string input)
		{
			if (!string.IsNullOrEmpty(input))
			{
				return Regex.Split(input, "(\\s+)").ToList();
			}
			return new List<string>();
		}

		private void ApplySingleWordColoring(List<string> tokens)
		{
			Dictionary<string, string> dictionary = KeywordColors.Where<KeyValuePair<string, string>>((KeyValuePair<string, string> kvp) => !kvp.Key.Contains(" ")).ToDictionary((KeyValuePair<string, string> k) => k.Key.ToLowerInvariant(), (KeyValuePair<string, string> v) => v.Value);
			for (int num = 0; num < tokens.Count; num++)
			{
				string text = tokens[num];
				if (IsWord(text))
				{
					string key = Regex.Replace(text.ToLowerInvariant(), "[^a-z0-9]", "");
					if (dictionary.TryGetValue(key, out var value))
					{
						tokens[num] = "<color=" + value + ">" + text + "</color>";
					}
				}
			}
		}

		private void ApplyMultiWordColoring(List<string> tokens)
		{
			List<KeyValuePair<string, string>> list = (from k in KeywordColors
				where k.Key.Contains(" ")
				orderby k.Key.Length descending
				select k).ToList();
			if (list.Count == 0)
			{
				return;
			}
			for (int num = 0; num < tokens.Count; num++)
			{
				if (!IsWord(tokens[num]))
				{
					continue;
				}
				string text = string.Concat(tokens.Skip(num)).ToLowerInvariant();
				foreach (KeyValuePair<string, string> item in list)
				{
					if (!text.StartsWith(item.Key.ToLowerInvariant()))
					{
						continue;
					}
					int num2 = 0;
					string text2 = "";
					for (int num3 = num; num3 < tokens.Count; num3++)
					{
						if (text2.Length >= item.Key.Length)
						{
							break;
						}
						text2 += tokens[num3];
						num2++;
					}
					tokens[num] = "<color=" + item.Value + ">" + text2 + "</color>";
					for (int num4 = 1; num4 < num2; num4++)
					{
						tokens[num + num4] = "";
					}
					num += num2 - 1;
					break;
				}
			}
		}

		private bool IsWord(string token)
		{
			return !string.IsNullOrWhiteSpace(token);
		}

		public void Log(string text)
		{
			ManualLogSource? logger = PluginMain.logger;
			if (logger != null)
			{
				logger.LogInfo((object)text);
			}
			string colorizedMessage = Colorize(text);
			LogEntry item = new LogEntry(text)
			{
				msg = colorizedMessage
			};
			_historyEntries.Add(item);
			if (_historyEntries.Count > 1000)
			{
				_historyEntries.RemoveAt(0);
				_historyBuiltCount = Mathf.Max(0, _historyBuiltCount - 1);
			}
			if (_showHistory)
			{
				_rebuildHistoryDirty = true;
			}
			else
			{
				_cachedEntries.Enqueue(item);
			}
		}

		public void DebugLog(string text)
		{
			if (PluginMain.EnableDebugLogging)
			{
				Log(text);
			}
		}

		private void ToggleHistory()
		{
			_showHistory = !_showHistory;
			if ((Object)(object)_messageParent == (Object)null || (Object)(object)_historyPanel == (Object)null)
			{
				return;
			}
			((Component)_messageParent).gameObject.SetActive(!_showHistory);
			_historyPanel.SetActive(_showHistory);
			if (_showHistory)
			{
				foreach (LogEntry visibleEntry in _visibleEntries)
				{
					if ((Object)(object)visibleEntry.text != (Object)null)
					{
						((Component)visibleEntry.text).gameObject.SetActive(false);
						_textPool.Enqueue(visibleEntry.text);
					}
					if ((Object)(object)visibleEntry.background != (Object)null)
					{
						((Component)visibleEntry.background).gameObject.SetActive(false);
						_backgroundPool.Enqueue(visibleEntry.background);
					}
				}
				_visibleEntries.Clear();
				_cachedEntries = new ConcurrentQueue<LogEntry>();
				RebuildHistory();
			}
			else
			{
				Cursor.lockState = (CursorLockMode)1;
				Cursor.visible = false;
				((Component)_messageParent).gameObject.SetActive(_showConsole);
			}
		}

		private void ToggleConsole()
		{
			_showConsole = !_showConsole;
			if ((Object)(object)_messageParent == (Object)null || (Object)(object)_historyPanel == (Object)null)
			{
				return;
			}
			foreach (LogEntry visibleEntry in _visibleEntries)
			{
				if ((Object)(object)visibleEntry.background != (Object)null)
				{
					((Component)visibleEntry.background).gameObject.SetActive(_showConsole);
				}
				if ((Object)(object)visibleEntry.text != (Object)null)
				{
					((Component)visibleEntry.text).gameObject.SetActive(_showConsole);
				}
			}
			((Component)_messageParent).gameObject.SetActive(_showConsole);
			if (!_showConsole)
			{
				_showHistory = false;
				_historyPanel.SetActive(false);
			}
		}

		private void BuildUI()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("APConsoleCanvas", new Type[3]
			{
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			val.transform.SetParent(((Component)this).transform);
			Canvas component = val.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 2000;
			CanvasScaler component2 = val.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			GameObject val2 = new GameObject("Messages", new Type[1] { typeof(RectTransform) });
			RectTransform component3 = val2.GetComponent<RectTransform>();
			((Transform)component3).SetParent(val.transform, false);
			_messageParent = val2.transform;
			PositionMessageContainer(component3);
			_historyPanel = new GameObject("HistoryPanel", new Type[1] { typeof(RectTransform) });
			RectTransform component4 = _historyPanel.GetComponent<RectTransform>();
			((Transform)component4).SetParent(val.transform, false);
			PositionHistoryPanel(component4);
			_historyPanel.SetActive(false);
			_historyScrollRect = _historyPanel.AddComponent<ScrollRect>();
			_historyScrollRect.horizontal = false;
			_historyScrollRect.vertical = true;
			_historyScrollRect.scrollSensitivity = 5f;
			_historyScrollRect.movementType = (MovementType)2;
			GameObject val3 = new GameObject("Viewport", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Mask)
			});
			_historyViewport = val3.GetComponent<RectTransform>();
			val3.transform.SetParent(_historyPanel.transform, false);
			_historyViewport.anchorMin = Vector2.zero;
			_historyViewport.anchorMax = Vector2.one;
			RectTransform? historyViewport = _historyViewport;
			Vector2 offsetMin = (_historyViewport.offsetMax = Vector2.zero);
			historyViewport.offsetMin = offsetMin;
			Image component5 = val3.GetComponent<Image>();
			((Graphic)component5).color = _backColor;
			component5.type = (Type)0;
			((Graphic)component5).raycastTarget = true;
			val3.GetComponent<Mask>().showMaskGraphic = false;
			_historyScrollRect.viewport = _historyViewport;
			GameObject val4 = new GameObject("Content", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			RectTransform component6 = val4.GetComponent<RectTransform>();
			((Transform)component6).SetParent(val3.transform, false);
			component6.anchorMin = new Vector2(0f, 1f);
			component6.anchorMax = new Vector2(1f, 1f);
			component6.pivot = new Vector2(0.5f, 1f);
			component6.anchoredPosition = Vector2.zero;
			component6.sizeDelta = new Vector2(0f, 0f);
			VerticalLayoutGroup component7 = val4.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component7).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component7).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)component7).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)component7).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component7).spacing = 2f;
			((LayoutGroup)component7).childAlignment = (TextAnchor)0;
			ContentSizeFitter component8 = val4.GetComponent<ContentSizeFitter>();
			component8.verticalFit = (FitMode)2;
			component8.horizontalFit = (FitMode)0;
			_historyScrollRect.content = component6;
			_historyContent = component6;
		}

		private void RebuildHistory()
		{
			if (!((Object)(object)_historyContent == (Object)null))
			{
				for (int i = _historyBuiltCount; i < _historyEntries.Count; i++)
				{
					AddHistoryEntryVisual(_historyEntries[i]);
				}
				_historyBuiltCount = _historyEntries.Count;
				Canvas.ForceUpdateCanvases();
				LayoutRebuilder.ForceRebuildLayoutImmediate(_historyContent);
				Canvas.ForceUpdateCanvases();
				if ((Object)(object)_historyScrollRect != (Object)null)
				{
					_historyScrollRect.verticalNormalizedPosition = 0f;
				}
			}
		}
	}
	public class ArchipelagoHandler : MonoBehaviour
	{
		public static ArchipelagoHandler Instance;

		private ArchipelagoSession? _session;

		public SlotData? slotData;

		public static Action? OnDisconnect;

		private ConcurrentQueue<long> _locationsToCheck = new ConcurrentQueue<long>();

		public volatile bool connectionFinished = true;

		public volatile bool connectionSucceeded;

		private readonly bool _queueBreak;

		private bool _shouldDisconnect;

		private string? _lastDeath;

		private DateTime _lastDeathTime = DateTime.Now;

		public string? Server { get; set; }

		public string? Slot { get; set; }

		public string? Password { get; set; }

		public string? Seed { get; set; }

		public bool IsConnected
		{
			get
			{
				ArchipelagoSession? session = _session;
				if (session == null)
				{
					return false;
				}
				return session.Socket.Connected;
			}
		}

		public event Action<string, string>? OnConnected;

		public event Action<string>? OnConnectionFailed;

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
			else
			{
				Instance = this;
			}
		}

		private void Update()
		{
			if (_shouldDisconnect)
			{
				_shouldDisconnect = false;
				Disconnect();
			}
		}

		public bool CreateSession(string server, string slot, string password)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			Server = server;
			Slot = slot;
			Password = password;
			_locationsToCheck = new ConcurrentQueue<long>();
			_shouldDisconnect = false;
			connectionSucceeded = false;
			connectionFinished = false;
			try
			{
				_session = ArchipelagoSessionFactory.CreateSession(Server, 38281);
			}
			catch (Exception)
			{
				return false;
			}
			_session.MessageLog.OnMessageReceived += new MessageReceivedHandler(OnMessageReceived);
			_session.Socket.ErrorReceived += new ErrorReceivedHandler(OnError);
			_session.Socket.SocketClosed += new SocketClosedHandler(OnSocketClosed);
			_session.Items.ItemReceived += new ItemReceivedHandler(ItemReceived);
			_session.Socket.PacketReceived += new PacketReceivedHandler(OnPacketReceived);
			return true;
		}

		private IEnumerator ConnectRoutine()
		{
			APConsole.Instance.Log("Logging in to " + Server + " as " + Slot + "...");
			Task<RoomInfoPacket> connectTask = _session.ConnectAsync();
			yield return (object)new WaitUntil((Func<bool>)(() => connectTask.IsCompleted));
			if (connectTask.IsFaulted || connectTask.IsCanceled)
			{
				string text = connectTask.Exception?.InnerException?.Message ?? "Took too long...";
				Debug.Log((object)("Connection Error: " + text));
				connectionSucceeded = false;
				connectionFinished = true;
				this.OnConnectionFailed?.Invoke(text);
				yield break;
			}
			Seed = connectTask.Result.SeedName;
			Task<LoginResult> loginTask = _session.LoginAsync("Crashout Crew", Slot, (ItemsHandlingFlags)7, new Version(0, 6, 7), Array.Empty<string>(), (string)null, Password, true);
			yield return (object)new WaitUntil((Func<bool>)(() => loginTask.IsCompleted));
			if (loginTask.IsFaulted || loginTask.IsCanceled)
			{
				string text2 = loginTask.Exception?.InnerException?.Message ?? "Took too long...";
				APConsole.Instance.Log("Login Error: " + text2);
				connectionSucceeded = false;
				connectionFinished = true;
				yield break;
			}
			if (loginTask.Result.Successful)
			{
				APConsole.Instance.Log("Successfully connected to " + Server + "!");
				LoginSuccessful val = (LoginSuccessful)loginTask.Result;
				slotData = new SlotData(val.SlotData);
				((MonoBehaviour)Instance).StartCoroutine(RunCheckQueue());
				connectionSucceeded = true;
				connectionFinished = true;
				this.OnConnected?.Invoke(Seed, Slot);
				yield break;
			}
			connectionSucceeded = false;
			connectionFinished = true;
			if (loginTask.Result != null)
			{
				LoginFailure val2 = (LoginFailure)loginTask.Result;
				string seed = "Failed to connect to " + Server + " with " + Slot + ".";
				seed = val2.Errors.Aggregate(seed, (string current, string error) => current + "\n    " + error);
				seed = val2.ErrorCodes.Aggregate(seed, (string current, ConnectionRefusedError error) => current + $"\n    {error}");
				this.OnConnectionFailed?.Invoke(seed);
				APConsole.Instance.Log(seed);
			}
			APConsole.Instance.Log("Attempting to reconnect...");
		}

		private void OnDestroy()
		{
			Disconnect();
		}

		public void Connect()
		{
			((MonoBehaviour)this).StartCoroutine(ConnectRoutine());
		}

		public void Disconnect()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			if (_session != null)
			{
				_session.MessageLog.OnMessageReceived -= new MessageReceivedHandler(OnMessageReceived);
				_session.Socket.ErrorReceived -= new ErrorReceivedHandler(OnError);
				_session.Socket.SocketClosed -= new SocketClosedHandler(OnSocketClosed);
				_session.Items.ItemReceived -= new ItemReceivedHandler(ItemReceived);
				_session.Socket.PacketReceived -= new PacketReceivedHandler(OnPacketReceived);
				ItemHandler.Instance.Reset();
				PluginMain.SaveDataHandler?.Reset();
				try
				{
					_session.Socket.DisconnectAsync();
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("Error during async disconnect: " + ex.Message));
				}
				_session = null;
				((MonoBehaviour)this).StopAllCoroutines();
				OnDisconnect?.Invoke();
				APConsole.Instance.Log("Disconnected from Archipelago!");
			}
		}

		private void OnError(Exception exception, string message)
		{
			Debug.LogWarning((object)exception);
			APConsole.Instance.Log("Socket Error: " + message + " - " + exception.Message);
			if ((exception is SocketException || exception is WebSocketException) ? true : false)
			{
				_shouldDisconnect = true;
			}
		}

		private void OnSocketClosed(string reason)
		{
			_shouldDisconnect = true;
		}

		private void ItemReceived(ReceivedItemsHelper helper)
		{
			try
			{
				while (helper.Any())
				{
					int index = helper.Index;
					ItemInfo item = helper.DequeueItem();
					ItemHandler.Instance.EnqueueItem(index, item);
				}
			}
			catch (Exception arg)
			{
				APConsole.Instance.Log($"[Item Received ERROR] {arg}");
				throw;
			}
		}

		public void Release()
		{
			ArchipelagoSession? session = _session;
			if (session != null)
			{
				session.SetGoalAchieved();
			}
			ArchipelagoSession? session2 = _session;
			if (session2 != null)
			{
				session2.SetClientState((ArchipelagoClientState)30);
			}
		}

		public void CheckLocation(long id)
		{
			if (!IsLocationChecked(id))
			{
				_locationsToCheck.Enqueue(id);
			}
		}

		public void CheckLocations(long[] ids)
		{
			ids.ToList().ForEach(delegate(long id)
			{
				_locationsToCheck.Enqueue(id);
			});
		}

		private IEnumerator RunCheckQueue()
		{
			while (true)
			{
				if (_locationsToCheck.TryDequeue(out var result))
				{
					ArchipelagoSession? session = _session;
					if (session != null)
					{
						session.Locations.CompleteLocationChecks(new long[1] { result });
					}
				}
				if (_queueBreak)
				{
					break;
				}
				yield return (object)new WaitForSeconds(0.1f);
			}
		}

		private bool IsLocationChecked(long id)
		{
			ArchipelagoSession? session = _session;
			if (session == null)
			{
				return false;
			}
			return session.Locations.AllLocationsChecked.Contains(id);
		}

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

		public void UpdateTags(List<string> tags)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			ConnectUpdatePacket val = new ConnectUpdatePacket
			{
				Tags = tags.ToArray(),
				ItemsHandling = (ItemsHandlingFlags)7
			};
			ArchipelagoSession? session = _session;
			if (session != null)
			{
				session.Socket.SendPacket((ArchipelagoPacketBase)(object)val);
			}
		}

		private void OnMessageReceived(LogMessage message)
		{
			if (PluginMain.FilterLog)
			{
				PlayerSpecificLogMessage val = (PlayerSpecificLogMessage)(object)((message is PlayerSpecificLogMessage) ? message : null);
				if (val != null && !val.IsRelatedToActivePlayer)
				{
					return;
				}
			}
			string text;
			if (message.Parts.Length == 1)
			{
				text = message.Parts[0].Text;
			}
			else
			{
				StringBuilder stringBuilder = new StringBuilder();
				MessagePart[] parts = message.Parts;
				foreach (MessagePart val2 in parts)
				{
					stringBuilder.Append(val2.Text ?? "");
				}
				text = stringBuilder.ToString();
			}
			APConsole.Instance.Log(text);
		}

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

		public ScoutedItemInfo? TryScoutLocation(long locationId, bool createHint = false)
		{
			ArchipelagoSession? session = _session;
			if (session == null)
			{
				return null;
			}
			return session.Locations.ScoutLocationsAsync(createHint, new long[1] { locationId })?.Result?.Values.First();
		}

		public void SendDeath()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			APConsole.Instance.Log("SendDeath called!");
			SlotData? obj = slotData;
			if (obj == null || obj.DeathLink)
			{
				return;
			}
			BouncePacket val = new BouncePacket();
			DateTime now = DateTime.Now;
			if (!(now - _lastDeathTime < TimeSpan.FromSeconds(2.0)))
			{
				val.Tags = new List<string>(1) { "DeathLink" };
				val.Data = new Dictionary<string, JToken>
				{
					{
						"time",
						JToken.op_Implicit(UnixTimeConverter.ToUnixTimeStamp(now))
					},
					{
						"source",
						JToken.op_Implicit(Slot)
					},
					{
						"cause",
						JToken.op_Implicit("Death")
					}
				};
				_lastDeathTime = now;
				ArchipelagoSession? session = _session;
				if (session != null)
				{
					session.Socket.SendPacket((ArchipelagoPacketBase)(object)val);
				}
			}
		}

		private void BouncePacketReceived(BouncePacket packet)
		{
			if (_lastDeath == null)
			{
				_lastDeathTime = DateTime.Now;
			}
			SlotData? obj = slotData;
			if (obj != null && obj.DeathLink)
			{
				ProcessBouncePacket(packet, "DeathLink", ref _lastDeath, delegate(string source, Dictionary<string, JToken> data)
				{
					HandleDeathLink(source, ((object)data["cause"])?.ToString() ?? "Unknown");
				});
			}
		}

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

		private void HandleDeathLink(string source, string cause)
		{
			SlotData? obj = slotData;
			if (obj != null && obj.DeathLink && !(source == Slot))
			{
				Kill();
			}
		}

		public void Kill()
		{
			APConsole.Instance.Log("Player Killed!!!");
		}

		public void Reset()
		{
			connectionFinished = true;
			connectionSucceeded = false;
		}
	}
	public static class ContractGenerator
	{
		private static readonly List<(string, string)> Warehouses = new List<(string, string)>(10)
		{
			("Assets/Scenes/scene-Dumbbell_1-2.unity", "Assets/Scenes/scene-Dumbbell.unity"),
			("Assets/Scenes/scene-IPiece_1-2.unity", "Assets/Scenes/scene-IPiece.unity"),
			("Assets/Scenes/scene-SBendMini_1-2.unity", "Assets/Scenes/scene-SBendMini.unity"),
			("Assets/Scenes/scene-ConveyorBlock.unity", "Assets/Scenes/scene-ConveyorBlock.unity"),
			("Assets/Scenes/scene-ConveyorHallway.unity", "Assets/Scenes/scene-ConveyorHallway.unity"),
			("Assets/Scenes/scene-ConveyorLoop.unity", "Assets/Scenes/scene-ConveyorLoop.unity"),
			("Assets/Scenes/scene-Figure8RaceTrackMini.unity", "Assets/Scenes/scene-Figure8RaceTrackMini.unity"),
			("Assets/Scenes/scene-LBendRaceTrackMini.unity", "Assets/Scenes/scene-LBendRaceTrackMini.unity"),
			("Assets/Scenes/scene-RaceTrackMini.unity", "Assets/Scenes/scene-RaceTrackMini.unity"),
			("Assets/Scenes/scene-UBendMiniRacetrack.unity", "Assets/Scenes/scene-UBendMiniRacetrack.unity")
		};

		private static readonly int[] OutboundDeliveryCount = new int[5] { 4, 5, 6, 7, 8 };

		public static ContractObject[] GenerateContracts(Random random, ShiftOrderObject[] allOrders, int twoOrderContracts, int threeOrderContracts, int fourOrderContracts)
		{
			List<int> list = new List<int>();
			list.AddRange(Enumerable.Repeat(2, twoOrderContracts));
			list.AddRange(Enumerable.Repeat(3, threeOrderContracts));
			list.AddRange(Enumerable.Repeat(4, fourOrderContracts));
			List<int> list2 = list.OrderBy((int _) => random.Next()).ToList();
			List<ContractObject> list3 = new List<ContractObject>();
			List<ShiftOrderObject> list4 = new List<ShiftOrderObject>();
			foreach (int item2 in list2)
			{
				List<ShiftOrderObject> selectedOrders = new List<ShiftOrderObject>();
				while (selectedOrders.Count < item2)
				{
					if (list4.Count == 0)
					{
						list4.AddRange(allOrders.OrderBy((ShiftOrderObject _) => random.Next()));
					}
					ShiftOrderObject item = ((IEnumerable<ShiftOrderObject>)list4).FirstOrDefault((Func<ShiftOrderObject, bool>)((ShiftOrderObject o) => !selectedOrders.Contains(o)));
					list4.Remove(item);
					selectedOrders.Add(item);
				}
				list3.Add(GenerateContract(random, selectedOrders.ToArray()));
			}
			list3 = list3.OrderBy((ContractObject x) => x.orders.Length).ToList();
			for (int num = 0; num < list3.Count; num++)
			{
				list3[num].bellsRequired = 5 * num;
			}
			return list3.ToArray();
		}

		private static ContractObject GenerateContract(Random random, ShiftOrderObject[] orders)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			ContractObject val = ScriptableObject.CreateInstance<ContractObject>();
			val.title = orders.GenerateName(random);
			((Object)val).name = val.title.Replace(' ', '_').ToUpper();
			val.modifierMultiplier = 1f;
			val.type = (ContractType)0;
			val.orders = orders;
			(string, string) tuple = Warehouses.Random(0, -1, random);
			val.smallWarehouse = tuple.Item1;
			val.bigWarehouse = tuple.Item2;
			val.multiplierForOnePlayer = 0.4f;
			val.multiplierForTwoPlayers = 0.7f;
			val.multiplierForThreePlayers = 0.85f;
			val.shift1 = GenerateShift(random, val, orders, 0);
			val.shift2 = GenerateShift(random, val, orders, 1);
			val.shift3 = GenerateShift(random, val, orders, 2);
			val.shift4 = GenerateShift(random, val, orders, 3);
			val.shift5 = GenerateShift(random, val, orders, 4);
			val.shopCards = Array.Empty<DeckCard<ShopItemObject>>();
			val.unlocks = Array.Empty<Unlock>();
			val.demoVisualPrefabs = Array.Empty<GameObject>();
			return val;
		}

		private static ContractShift GenerateShift(Random random, ContractObject contract, ShiftOrderObject[] orders, int shiftIndex)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			ContractShift val = new ContractShift();
			List<Outbound> list = new List<Outbound>();
			List<Inbound> list2 = new List<Inbound>();
			List<Order> list3 = new List<Order>();
			val.owner = contract;
			val.truckPatienceDuration = random.Next(90, 110);
			int num = OutboundDeliveryCount[shiftIndex];
			for (int i = 0; i < num; i++)
			{
				int num2 = random.Next(4, 7);
				list.Add(new Outbound
				{
					bayCount = 1,
					boxCount = num2,
					secondsFromPrevious = random.Next(8, 14)
				});
				int num3 = random.Next(1, 3);
				int boxCount = Mathf.CeilToInt((float)(num2 + random.Next(0, 3)) / (float)num3);
				list2.Add(new Inbound
				{
					bayCount = num3,
					boxCount = boxCount,
					normalizedTime = (float)i * (0.75f / (float)num)
				});
			}
			val.outbound = list.ToArray();
			val.inbound = list2.ToArray();
			val.payOutAmount = num * random.Next(75, 115);
			foreach (ShiftOrderObject order in orders)
			{
				int minValue = ((shiftIndex >= 4) ? 1 : 0);
				list3.Add(new Order
				{
					owner = contract,
					order = order,
					randomOrderIndex = 1,
					cardCount = random.Next(minValue, 3)
				});
			}
			if (list3.All((Order x) => x.cardCount == 0))
			{
				list3.Random(0, -1, random).cardCount = 1;
			}
			val.orders = list3.ToArray();
			return val;
		}
	}
	public static class ContractNameGenerator
	{
		private static readonly Dictionary<string, string[]> OrderToAdjectives = new Dictionary<string, string[]>
		{
			{
				"order-anvil",
				new string[2] { "Heavy", "Hard" }
			},
			{
				"order-barreloil",
				new string[2] { "Gloopy", "Sticky" }
			},
			{
				"order-barrelooze",
				new string[1] { "Corrosive" }
			},
			{
				"order-battery",
				new string[2] { "Speedy", "Powerful" }
			},
			{
				"order-beehive",
				new string[2] { "Buzzy", "Stingy" }
			},
			{
				"order-bingbong",
				new string[2] { "Bingy", "Bongy" }
			},
			{
				"order-blueberry",
				new string[4] { "Blueish", "Tasty", "Fruity", "Squishy" }
			},
			{
				"order-bomb",
				new string[2] { "Dangerous", "Bangy" }
			},
			{
				"order-bull",
				new string[2] { "Bullish", "Horny" }
			},
			{
				"order-cherry",
				new string[4] { "Red", "Tasty", "Fruity", "Squishy" }
			},
			{
				"order-chicken",
				new string[2] { "Feathery", "BKAWK" }
			},
			{
				"order-clownCar",
				new string[2] { "Fast", "Furious" }
			},
			{
				"order-cubeToy",
				new string[2] { "Colorful", "Cubic" }
			},
			{
				"order-egg",
				new string[2] { "Eggy", "Cracked" }
			},
			{
				"order-fireworks",
				new string[2] { "Pretty", "Sparkly" }
			},
			{
				"order-ghostBox",
				new string[4] { "Haunted", "Spooky", "Ghostly", "Scary" }
			},
			{
				"order-grape",
				new string[5] { "Purple", "Grapey", "Squishy", "Fruity", "Tasty" }
			},
			{
				"order-honeyPot",
				new string[2] { "Sweet", "Sticky" }
			},
			{
				"order-kiwi",
				new string[5] { "Green", "Fuzzy", "Squishy", "Fruity", "Tasty" }
			},
			{
				"order-lantern",
				new string[3] { "Bright", "Hot", "Fiery" }
			},
			{
				"order-monkey",
				new string[2] { "Cheeky", "Sneaky" }
			},
			{
				"order-snail",
				new string[3] { "Slimy", "Slow", "Shelly" }
			},
			{
				"order-vase",
				new string[2] { "Fragile", "Expensive" }
			}
		};

		private static readonly Dictionary<string, string[]> OrderToVerb = new Dictionary<string, string[]>
		{
			{
				"order-anvil",
				new string[2] { "Falling", "Crushing" }
			},
			{
				"order-barreloil",
				new string[2] { "Spilling", "Oozing" }
			},
			{
				"order-barrelooze",
				new string[2] { "Burning", "Oozing" }
			},
			{
				"order-battery",
				new string[2] { "Energizing", "Powering" }
			},
			{
				"order-beehive",
				new string[1] { "Buzzing" }
			},
			{
				"order-bingbong",
				new string[2] { "Crying", "Squeaking" }
			},
			{
				"order-blueberry",
				Array.Empty<string>()
			},
			{
				"order-bomb",
				new string[2] { "Exploding", "Detonating" }
			},
			{
				"order-bull",
				new string[3] { "Charging", "Bucking", "Bullying" }
			},
			{
				"order-cherry",
				Array.Empty<string>()
			},
			{
				"order-chicken",
				new string[2] { "Clucking", "Laying" }
			},
			{
				"order-clownCar",
				new string[2] { "Honking", "Driving" }
			},
			{
				"order-cubeToy",
				new string[2] { "Solving", "Scrambling" }
			},
			{
				"order-egg",
				new string[2] { "Cracking", "Frying" }
			},
			{
				"order-fireworks",
				new string[3] { "Exploding", "Flying", "Whistling" }
			},
			{
				"order-ghostBox",
				new string[2] { "Spooking", "Scaring" }
			},
			{
				"order-grape",
				Array.Empty<string>()
			},
			{
				"order-honeyPot",
				new string[1] { "Sticking" }
			},
			{
				"order-kiwi",
				Array.Empty<string>()
			},
			{
				"order-lantern",
				new string[3] { "Lighting", "Flaming", "Glowing" }
			},
			{
				"order-monkey",
				new string[2] { "Swinging", "Throwing" }
			},
			{
				"order-snail",
				new string[1] { "Crawling" }
			},
			{
				"order-vase",
				new string[2] { "Smashing", "Breaking" }
			}
		};

		private static readonly Dictionary<string, string[]> OrderToNoun = new Dictionary<string, string[]>
		{
			{
				"order-anvil",
				new string[3] { "Anvils", "Weights", "Metal" }
			},
			{
				"order-barreloil",
				new string[3] { "Oil", "Barrels", "Mess" }
			},
			{
				"order-barrelooze",
				new string[3] { "Acid", "Barrels", "Waste" }
			},
			{
				"order-battery",
				new string[3] { "Batteries", "Energy", "Power" }
			},
			{
				"order-beehive",
				new string[3] { "Bees", "Hives", "Buzzers" }
			},
			{
				"order-bingbong",
				new string[2] { "BingBong", "Husband" }
			},
			{
				"order-blueberry",
				new string[2] { "Blueberries", "Fruit" }
			},
			{
				"order-bomb",
				new string[3] { "Bombs", "Explosives", "Destruction" }
			},
			{
				"order-bull",
				new string[3] { "Bulls", "Animals", "Horns" }
			},
			{
				"order-cherry",
				new string[2] { "Cherries", "Fruit" }
			},
			{
				"order-chicken",
				new string[3] { "Chickens", "Cluckers", "Feathers" }
			},
			{
				"order-clownCar",
				new string[3] { "Cars", "Drivers", "Wheels" }
			},
			{
				"order-cubeToy",
				new string[3] { "Cubes", "Puzzles", "Solvers" }
			},
			{
				"order-egg",
				new string[2] { "Eggs", "Shells" }
			},
			{
				"order-fireworks",
				new string[3] { "Fireworks", "Explosives", "Lights" }
			},
			{
				"order-ghostBox",
				new string[3] { "Ghosts", "Ghouls", "Haunt" }
			},
			{
				"order-grape",
				new string[2] { "Grapes", "Fruit" }
			},
			{
				"order-honeyPot",
				new string[2] { "Honey", "Pots" }
			},
			{
				"order-kiwi",
				new string[2] { "Kiwis", "Fruit" }
			},
			{
				"order-lantern",
				new string[3] { "Lanterns", "Fire", "Lights" }
			},
			{
				"order-monkey",
				new string[3] { "Monkeys", "Bananas", "Peels" }
			},
			{
				"order-snail",
				new string[2] { "Snails", "Shells" }
			},
			{
				"order-vase",
				new string[2] { "Vases", "Pots" }
			}
		};

		public static string GenerateName(this ShiftOrderObject[] orders, Random random)
		{
			List<string> list = new List<string>();
			for (int i = 0; i < orders.Length; i++)
			{
				if (i == orders.Length - 1)
				{
					list.Add(OrderToNoun[((Object)orders[i]).name].Random(0, -1, random));
					break;
				}
				if (i == orders.Length - 2 && OrderToVerb[((Object)orders[i]).name].Length != 0)
				{
					list.Add(OrderToVerb[((Object)orders[i]).name].Random(0, -1, random));
				}
				else
				{
					list.Add(OrderToAdjectives[((Object)orders[i]).name].Random(0, -1, random));
				}
			}
			return string.Join(" ", list);
		}
	}
	public static class CostumeHandler
	{
		private static readonly Random Random = new Random();

		public static void SelectRandom()
		{
			Entity val = default(Entity);
			if (GameUtil.TryGetLocalPlayer(ref val))
			{
				PlayerCostumeManager val2 = ((Entity)(ref val)).GetObject<PlayerCostumeManager>();
				PlayerCostumeManagerNetwork val3 = ((Entity)(ref val)).GetObject<PlayerCostumeManagerNetwork>();
				val2.SetUpUnlockedIndicies();
				int currentUnlockedCostumeIndex = Random.Next(val2.unlockedCostumeIndicies.Length);
				val2.currentUnlockedCostumeIndex = currentUnlockedCostumeIndex;
				val3.SetCostumeIndex(val2.unlockedCostumeIndicies[val2.currentUnlockedCostumeIndex]);
				val2.ResetAllCostumes();
				SaveManager.data.SetCurrentCostume(val2.costumes[val3.currentCostumeID].costumeObject);
			}
		}
	}
	public enum CCItem
	{
		Bell = 1,
		Boost = 2,
		Charge = 3,
		Button = 4,
		Extinguisher = 5,
		Scrub = 6,
		Scrubbie = 7,
		Shelf = 8,
		Sprinkler = 9,
		Sturdy = 10,
		Tele = 11,
		Trash = 12,
		Vac = 13,
		Leaf = 14,
		XlSprinkler = 15,
		WaterBalloon = 16,
		Wild = 17,
		Nitro = 18,
		Aroma = 19,
		Drift = 20,
		Shield = 21,
		Chain = 22,
		Cup = 23,
		Fan = 24,
		Grip = 25,
		Spoiler = 26,
		Cosmetic = 32,
		SpeedUpgrade = 48,
		StrengthUpgrade = 49,
		BoostUpgrade = 50,
		StressUpgrade = 51
	}
	public class ItemHandler : MonoBehaviour
	{
		public static ItemHandler Instance;

		private readonly ConcurrentQueue<(int, ItemInfo)> _cachedItems = new ConcurrentQueue<(int, ItemInfo)>();

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
			else
			{
				Instance = this;
			}
		}

		public void Reset()
		{
			_cachedItems.Clear();
		}

		public void EnqueueItem(int itemIndex, ItemInfo item)
		{
			_cachedItems.Enqueue((itemIndex, item));
		}

		private bool IsReady()
		{
			if (ArchipelagoHandler.Instance.IsConnected)
			{
				return PluginMain.SaveDataHandler?.APSaveData != null;
			}
			return false;
		}

		private void Update()
		{
			(int, ItemInfo) result;
			while (IsReady() && _cachedItems.TryDequeue(out result))
			{
				HandleItem(result.Item1, result.Item2);
			}
		}

		private void HandleItem(int index, ItemInfo item)
		{
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Invalid comparison between Unknown and I4
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Invalid comparison between Unknown and I4
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Invalid comparison between I4 and Unknown
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0493: 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_04b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_04dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
			if (index <= PluginMain.SaveDataHandler.APSaveData.ItemIndex)
			{
				return;
			}
			switch ((CCItem)item.ItemId)
			{
			case CCItem.Bell:
			{
				PluginMain.SaveDataHandler.APSaveData.Bells++;
				LobbyManager val = Object.FindObjectOfType<LobbyManager>();
				if (!((Object)(object)val != (Object)null) || !((NetworkBehaviour)val).isServer)
				{
					break;
				}
				val.Network_syncHostTotalBells = PluginMain.SaveDataHandler.APSaveData.Bells;
				val._syncUnlockList.Clear();
				int num = default(int);
				foreach (ContractObject allContract in val._allContracts)
				{
					if (allContract.isDemoLocked)
					{
						val._syncUnlockList.Add(false);
					}
					else if (val._syncHostTotalBells >= allContract.bellsRequired || ((int)allContract.type != 1 && SaveManager.data.TryGetContractBellCount(allContract, ref num) && num > 0))
					{
						val._syncUnlockList.Add(true);
					}
					else
					{
						val._syncUnlockList.Add(false);
					}
				}
				LobbyContractVisualManager val2 = Object.FindObjectOfType<LobbyContractVisualManager>();
				if ((Object)(object)val2 != (Object)null)
				{
					for (int i = 0; i < val2._contracts.Count; i++)
					{
						ContractObject val3 = val2._contracts[i];
						int num2 = (((int)val3.type == 1) ? val3.randomBoxCount : val3.orders.Length);
						LobbyOrderVisualStack val4 = ((Component)val2.contractVisualGroup).GetComponentsInChildren<LobbyOrderVisualStack>()[i];
						for (int j = 0; j < num2; j++)
						{
							Renderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<Renderer>();
							foreach (Renderer val5 in componentsInChildren)
							{
								if (val.IsContractUnlocked(i))
								{
									MaterialUtil.SetPropertyBlockFloat(val5, LobbyContractVisualManager.Locked, 0f);
								}
							}
						}
					}
				}
				ContractSelectionUI val6 = Object.FindObjectOfType<ContractSelectionUI>();
				if (!((Object)(object)val6 != (Object)null))
				{
					break;
				}
				int num3 = default(int);
				ContractScore val8 = default(ContractScore);
				TimeSpan zero = default(TimeSpan);
				for (int l = 0; l < val6._contracts.Count; l++)
				{
					ContractObject val7 = val6._contracts[l];
					if (!SaveManager.data.TryGetContractBellCount(val7, ref num3))
					{
						num3 = 0;
					}
					if (!SaveManager.data.TryGetContractScore(val7, ref val8))
					{
						val8 = (ContractScore)0;
					}
					if (!SaveManager.data.TryGetContractTime(val7, ref zero))
					{
						zero = TimeSpan.Zero;
					}
					ContractUI val9 = ((Component)val6.contractGroup).GetComponentsInChildren<ContractUI>()[l];
					if (val7.bellsRequired <= PluginMain.SaveDataHandler.APSaveData.Bells)
					{
						val9.lockedContainer.SetActive(false);
						val9.unlockedContainer.SetActive(true);
						val9.bellsRequiredContainer.SetActive(true);
						((TMP_Text)val9.bellsRequiredText).text = "";
						val9.localizedText.SetIndex(val7.title);
						((Component)val9.localizedText).gameObject.SetActive(true);
						val9.lockedText.SetActive(false);
						int num4 = ArchipelagoHandler.Instance.CountLocationsCheckedInRange(48 * l + 1, 48 * (l + 1) + 1);
						((TMP_Text)val9.contractNumText).text = $"{num4}/{35} locations - {l + 1}";
						((Behaviour)val9.contractNumText).enabled = true;
						for (int m = 0; m < val9.bells.Length; m++)
						{
							val9.bells[m].SetActive(m < (int)val8);
						}
						for (int n = 0; n < val9.scoreBubbles.Length; n++)
						{
							val9.scoreBubbles[n].scoreBubble.SetActive(false);
						}
						((Component)val9.finalGradeContainer).gameObject.SetActive(num3 > 0);
						val9.finalGradeImage.sprite = val9.gradeSprites[(num3 == 5) ? (val8 + 1) : 0];
						val9.finalGradeDillyImage.sprite = val9.gradeDillySprites[(num3 == 5) ? (val8 + 1) : 0];
						((Graphic)val9.finalGradeImage).color = GlobalScriptableObject<AggroSettingsObject>.instance.gradeColors[(num3 == 5) ? (val8 + 1) : 0];
						((Graphic)val9.finalGradeDillyImage).color = GlobalScriptableObject<AggroSettingsObject>.instance.gradeColors[(num3 == 5) ? (val8 + 1) : 0];
						if (num3 >= 5 && zero != TimeSpan.Zero)
						{
							((TMP_Text)val9.bestTimeText).text = zero.ToString("mm\\:ss\\:ff");
						}
						else
						{
							((TMP_Text)val9.bestTimeText).text = "--:--:--";
						}
					}
				}
				break;
			}
			case CCItem.Boost:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPBOOST");
				break;
			case CCItem.Charge:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPCHARGE");
				break;
			case CCItem.Button:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPBT");
				break;
			case CCItem.Extinguisher:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPFE");
				break;
			case CCItem.Scrub:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSCRUB");
				break;
			case CCItem.Scrubbie:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPROBO");
				break;
			case CCItem.Shelf:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSHELF");
				break;
			case CCItem.Sprinkler:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSMSPRINK");
				break;
			case CCItem.Sturdy:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSTURDY");
				break;
			case CCItem.Tele:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPTELE");
				break;
			case CCItem.Trash:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPTRASH");
				break;
			case CCItem.Vac:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPVAC");
				break;
			case CCItem.Leaf:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPLEAF");
				break;
			case CCItem.XlSprinkler:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPXLSPRINK");
				break;
			case CCItem.WaterBalloon:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPWBP");
				break;
			case CCItem.Wild:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPCARD");
				break;
			case CCItem.Nitro:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPBOOSTP");
				break;
			case CCItem.Aroma:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPDECAYP");
				break;
			case CCItem.Drift:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPDRIFTP");
				break;
			case CCItem.Shield:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPEXPP");
				break;
			case CCItem.Chain:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPTRACP");
				break;
			case CCItem.Cup:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSTRESSP");
				break;
			case CCItem.Fan:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPFIREP");
				break;
			case CCItem.Grip:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPGRIPP");
				break;
			case CCItem.Spoiler:
				PluginMain.SaveDataHandler.APSaveData.ShopUnlocks.Add("SHOPSPEEDP");
				break;
			case CCItem.Cosmetic:
				CostumeHandler.SelectRandom();
				break;
			case CCItem.SpeedUpgrade:
				PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades + 1, 3);
				break;
			case CCItem.StrengthUpgrade:
				PluginMain.SaveDataHandler.APSaveData.StrengthUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.StrengthUpgrades + 1, 3);
				SkysTheLimitAPI.SetStackLimit(PluginMain.SaveDataHandler.APSaveData.StrengthUpgrades + 3);
				break;
			case CCItem.BoostUpgrade:
				PluginMain.SaveDataHandler.APSaveData.BoostUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.BoostUpgrades + 1, 3);
				break;
			case CCItem.StressUpgrade:
				PluginMain.SaveDataHandler.APSaveData.StressUpgrades = Math.Min(PluginMain.SaveDataHandler.APSaveData.StressUpgrades + 1, 3);
				break;
			}
			PluginMain.SaveDataHandler.APSaveData.ItemIndex = index;
			PluginMain.SaveDataHandler.SaveGame();
		}
	}
	public class Localizer
	{
		public static void AddCustomLocalizations(string path)
		{
			Dictionary<string, List<string>> dictionary = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(File.ReadAllText(path));
			if (dictionary == null)
			{
				return;
			}
			foreach (KeyValuePair<string, List<string>> item in dictionary)
			{
				LocalizedText.mainTable.Add(item.Key, item.Value);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("crashout_crew_ap_client", "CrashoutCrew_APClient", "1.0.4")]
	public class PluginMain : BaseUnityPlugin
	{
		public static readonly int CONNECT_BUTTON_ID = AggroSettings.IdToHash("ap-connect");

		public static string? LocalizationsPath;

		public static bool EnableDebugLogging;

		public static bool FilterLog;

		public const string GameName = "CrashoutCrew";

		private const string Version = "1.0.4";

		private readonly Harmony _harmony = new Harmony("crashout_crew_ap_client");

		public static ManualLogSource? logger;

		public static SaveDataHandler? SaveDataHandler;

		public static Dictionary<string, AssetBundle> CustomBundles = new Dictionary<string, AssetBundle>();

		public static float MessageInTime
		{
			get
			{
				return APConsole.Instance.slideInTime;
			}
			set
			{
				APConsole.Instance.slideInTime = value;
			}
		}

		public static float MessageHoldTime
		{
			get
			{
				return APConsole.Instance.holdTime;
			}
			set
			{
				APConsole.Instance.holdTime = value;
			}
		}

		public static float MessageOutTime
		{
			get
			{
				return APConsole.Instance.fadeOutTime;
			}
			set
			{
				APConsole.Instance.fadeOutTime = value;
			}
		}

		private void Awake()
		{
			Enforcer.Enforce("crashout_crew_ap_client", "1.0.4", (EnforcementDirection)2);
			CustomBundles = new Dictionary<string, AssetBundle>();
			logger = ((BaseUnityPlugin)this).Logger;
			_harmony.PatchAll();
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			((Component)this).gameObject.AddComponent<ArchipelagoHandler>();
			((Component)this).gameObject.AddComponent<ItemHandler>();
			SaveDataHandler = ((Component)this).gameObject.AddComponent<SaveDataHandler>();
			ArchipelagoHandler.OnDisconnect = (Action)Delegate.Combine(ArchipelagoHandler.OnDisconnect, (Action)delegate
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene)).name != "scene-title")
				{
					SceneManager.LoadScene("scene-title");
				}
				GameManager_Patches.ClearContracts();
				AggroSettings.GetSetting<ButtonSetting>(CONNECT_BUTTON_ID).SetButtonLabel("Connect");
				AggroSettings.RefreshSettingUIs();
			});
			SceneManager.sceneLoaded += delegate
			{
				if (SaveDataHandler?.APSaveData != null)
				{
					SkysTheLimitAPI.SetStackLimit(SaveDataHandler.APSaveData.StrengthUpgrades + 3);
				}
			};
			string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			if (directoryName == null)
			{
				throw new Exception("Mod directory not found");
			}
			LocalizationsPath = Path.Combine(directoryName, "Localizations", "locs.json");
			if (!File.Exists(LocalizationsPath))
			{
				LocalizationsPath = Path.Combine(directoryName, "locs.json");
			}
			string[] obj = new string[2] { "aggro-button-setting", "aggro-text-setting" };
			string text = Path.Combine(directoryName, "Bundles");
			if (!Directory.Exists(text))
			{
				text = directoryName;
			}
			string[] array = obj;
			foreach (string text2 in array)
			{
				string text3 = Path.Combine(text, text2);
				if (!File.Exists(text3))
				{
					throw new Exception("Bundle " + text2 + " not found");
				}
				AssetBundle value = AssetBundle.LoadFromFile(text3);
				CustomBundles.Add(Path.GetFileNameWithoutExtension(text3), value);
			}
			SkysTheLimitAPI.SetStackLimit(3);
		}
	}
	public class CustomSaveData
	{
		public int ItemIndex;

		public readonly List<string> ShopUnlocks = new List<string>();

		public int Bells;

		public int SpeedUpgrades;

		public int StrengthUpgrades;

		public int BoostUpgrades;

		public int StressUpgrades;

		public int HandlingUpgrades;
	}
	public class SaveDataHandler : MonoBehaviour
	{
		public CustomSaveData? APSaveData;

		private string _customDataPath = "";

		public Action onInitialized;

		public void GetSave()
		{
			ArchipelagoHandler instance = ArchipelagoHandler.Instance;
			_customDataPath = Application.persistentDataPath + "/saves/Archipelago/" + instance.Slot + instance.Seed + ".json";
			if (!Directory.Exists(Path.GetDirectoryName(_customDataPath)))
			{
				Directory.CreateDirectory(Path.GetDirectoryName(_customDataPath));
			}
			if (File.Exists(_customDataPath))
			{
				APSaveData = JsonConvert.DeserializeObject<CustomSaveData>(File.ReadAllText(_customDataPath)) ?? new CustomSaveData();
				return;
			}
			APSaveData = new CustomSaveData();
			File.WriteAllText(_customDataPath, JsonConvert.SerializeObject((object)APSaveData));
		}

		public void SaveGame()
		{
			File.WriteAllText(_customDataPath, JsonConvert.SerializeObject((object)APSaveData));
			SaveManager.SaveGameAsync();
		}

		public void InitializeSave()
		{
			((MonoBehaviour)this).StartCoroutine(InitializeSaveCo());
		}

		private IEnumerator InitializeSaveCo()
		{
			if (APSaveData == null)
			{
				GetSave();
			}
			if (SaveManager.DoesGameExist(0))
			{
				APConsole.Instance.DebugLog("Save game exists!");
				Task<LoadResult> task = SaveManager.InitializeLoadGameAsync(0);
				yield return (object)new WaitForTask((Task)task);
				if ((int)task.Result != 0)
				{
					bool doContinue = false;
					bool doQuit = false;
					AggroInputManager.Enable();
					LoadResult result = task.Result;
					SaveError val;
					string text;
					if ((int)result != 1)
					{
						if ((int)result != 2)
						{
							throw new InvalidEnumException();
						}
						val = (SaveError)1;
						text = "";
					}
					else
					{
						val = (SaveError)0;
						text = new DateTime(SaveManager.data.timeStampTicks).ToString("g", CultureInfo.CurrentCulture);
					}
					PlayerMessageManager.QueueErrorMessage(val, text, (Action)delegate
					{
						doContinue = true;
					}, (Action)delegate
					{
						doQuit = true;
					});
					while (!doContinue && !doQuit)
					{
						PlayerMessageManager.ProcessQueuedMessages();
						yield return null;
					}
					AggroInputManager.Disable();
					if (doQuit)
					{
						Application.Quit();
						yield break;
					}
					if (doContinue)
					{
						result = task.Result;
						if ((int)result != 1)
						{
							if ((int)result != 2)
							{
								throw new InvalidEnumException();
							}
							yield return SaveManager.DeleteGameAsync(0);
							SaveManager.InitializeNewGame(0);
						}
						else
						{
							yield return SaveManager.DeletePrimarySaveAsync(0);
						}
						yield return SaveManager.SaveGameAsync();
					}
				}
				if (SaveManager.data.GetSaveVersion() != 1)
				{
					SaveManager.Uninitialize();
					SaveManager.InitializeNewGame(0);
					yield return (object)new WaitForTask(SaveManager.SaveGameAsync());
				}
			}
			else
			{
				APConsole.Instance.DebugLog("Save game does not exist!");
				SaveManager.InitializeNewGame(0);
				yield return (object)new WaitForTask(SaveManager.SaveGameAsync());
			}
			CostumeObject[] costumes = GlobalScriptableObject<CosmeticGlobalData>.instance.costumes;
			foreach (CostumeObject val2 in costumes)
			{
				if ((Object)(object)val2 != (Object)null && val2.startsUnlocked)
				{
					SaveManager.data.UnlockCostume(val2);
				}
			}
			onInitialized();
		}

		public void Reset()
		{
			SaveGame();
			APSaveData = null;
		}
	}
	public class SlotData
	{
		public readonly int ContractCountFour = 4;

		public readonly int ContractCountThree = 12;

		public readonly int ContractCountTwo = 4;

		public readonly bool DeathLink;

		public int ContractCount => ContractCountFour + ContractCountThree + ContractCountTwo;

		public SlotData(Dictionary<string, object> slotDict)
		{
			foreach (KeyValuePair<string, object> item in slotDict)
			{
				APConsole.Instance.DebugLog($"{item.Key} {item.Value}");
			}
			if (slotDict.TryGetValue("FourOrderContracts", out object value) && value is long num)
			{
				ContractCountFour = (int)num;
			}
			if (slotDict.TryGetValue("ThreeOrderContracts", out object value2) && value2 is long num2)
			{
				ContractCountThree = (int)num2;
			}
			if (slotDict.TryGetValue("TwoOrderContracts", out object value3) && value3 is long num3)
			{
				ContractCountTwo = (int)num3;
			}
		}
	}
	public static class Utility
	{
		public static T? Random<T>(this IEnumerable<T> collection, int rangeStart = 0, int rangeEnd = -1, Random? random = null)
		{
			T[] array = (collection as T[]) ?? collection.ToArray();
			if (array.Length != 0)
			{
				return array[random?.Next(0, array.Length - 1) ?? Random.Range(rangeStart, (rangeEnd == -1) ? array.Length : rangeEnd)];
			}
			return default(T);
		}

		public static T? Random<T>(this Array collection, int rangeStart = 0, int rangeEnd = -1, Random? random = null)
		{
			if (collection.Length != 0)
			{
				return (T)collection.GetValue(random?.Next(0, collection.Length - 1) ?? Random.Range(rangeStart, (rangeEnd == -1) ? collection.Length : rangeEnd));
			}
			return default(T);
		}
	}
}
namespace CrashoutCrew_APClient.Patches
{
	[HarmonyPatch(typeof(SteamPlatform))]
	public class AchievementManager_Patches
	{
		[HarmonyPatch("UnlockAchievement", new Type[] { typeof(string) })]
		[HarmonyPrefix]
		public static bool UnlockAchievement(string id)
		{
			return false;
		}
	}
	[HarmonyPatch(typeof(AggroSettingsObject))]
	public static class AggroSettingsObject_Patches
	{
		[HarmonyPatch("TryGetTemplate")]
		[HarmonyPostfix]
		public static void TryGetTemplate(Type type, ref GameObject template, ref bool __result)
		{
			AssetBundle value2;
			if ((typeof(TextSetting).IsAssignableFrom(type) || type.Name == "TextSetting") && PluginMain.CustomBundles.TryGetValue("aggro-text-setting", out AssetBundle value))
			{
				template = value.LoadAsset<GameObject>("prefab-aggrosetting-text");
				__result = (Object)(object)template != (Object)null;
			}
			else if ((typeof(ButtonSetting).IsAssignableFrom(type) || type.Name == "ButtonSetting") && PluginMain.CustomBundles.TryGetValue("aggro-button-setting", out value2))
			{
				template = value2.LoadAsset<GameObject>("prefab-aggrosetting-button");
				__result = (Object)(object)template != (Object)null;
			}
		}

		[HarmonyPatch("TryGetCategoryLabel")]
		[HarmonyPrefix]
		public static bool TryGetCategoryLabel(AggroSettingsObject __instance, ref bool __result, string category, out string label)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			__instance.CheckInitialize();
			if (!__instance._categoryToLabel.TryGetValue(category, out label))
			{
				List<Category> list = __instance.categories.ToList();
				list.Add(new Category());
				list.Last().category = category;
				label = category.Substring(0, 1).ToUpper() + category.Substring(1, category.Length - 1);
				list.Last().label = label;
				__instance.categories = list.ToArray();
			}
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(ContractUI))]
	public static class ContractUI_Patches
	{
		[HarmonyPatch("SetUp")]
		[HarmonyPostfix]
		public static void SetUp(ContractUI __instance, int contractNum)
		{
			int num = ArchipelagoHandler.Instance.CountLocationsCheckedInRange(48 * (contractNum - 1) + 1, 48 * contractNum + 1);
			((TMP_Text)__instance.contractNumText).text = $"{num}/{35} locations - {contractNum}";
		}

		[HarmonyPatch("SetUp")]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			MethodInfo methodInfo = AccessTools.Method(typeof(LocalizedText), "SetIndex", new Type[1] { typeof(string) }, (Type[])null);
			FieldInfo fieldInfo = AccessTools.Field(typeof(LocalizedText), "tmp");
			MethodInfo methodInfo2 = AccessTools.Method(typeof(TMP_Text), "set_text", (Type[])null, (Type[])null);
			for (int i = 0; i < list.Count; i++)
			{
				if (CodeInstructionExtensions.Calls(list[i], methodInfo))
				{
					if (i < 3 || list[i - 1].opcode != OpCodes.Ldarg_1)
					{
						throw new InvalidOperationException("ContractUI.SetUp: unexpected SetIndex IL pattern.");
					}
					list[i - 1] = new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo);
					list.Insert(i, new CodeInstruction(OpCodes.Ldarg_1, (object)null));
					list[i + 1] = new CodeInstruction(OpCodes.Callvirt, (object)methodInfo2);
					break;
				}
			}
			return list;
		}
	}
	[HarmonyPatch(typeof(CostumeChangeUI))]
	public static class CostumeChange_Patches
	{
		[HarmonyPatch("OnEntityCreated")]
		[HarmonyPrefix]
		public static bool OnEntityCreated(CostumeChangeUI __instance)
		{
			((Component)((Component)__instance).transform.parent).gameObject.SetActive(false);
			return false;
		}
	}
	[HarmonyPatch(typeof(GameManager))]
	public static class GameManager_Patches
	{
		private static readonly string[] Excluded = new string[1] { "order-bingbong" };

		public static DeckCard<ShopItemObject>[] ShopCards = null;

		private static ContractObject[]? _cachedContracts;

		public static void ClearContracts()
		{
			_cachedContracts = null;
		}

		[HarmonyPatch("GetContracts")]
		[HarmonyPrefix]
		public static bool GetContracts(GameManager __instance, ref ContractObject[] __result)
		{
			if (GameUtil.isDemo)
			{
				return true;
			}
			if (_cachedContracts != null)
			{
				__result = _cachedContracts;
				return false;
			}
			__result = Array.Empty<ContractObject>();
			ShopCards = __instance.contracts.Last().shopCards.ToArray();
			if (ArchipelagoHandler.Instance.Seed == null)
			{
				__result = __instance.contracts;
				return false;
			}
			Random random = new Random(int.Parse(ArchipelagoHandler.Instance.Seed.Substring(0, 9)));
			ShiftOrderObject[] allOrders = (from x in Resources.FindObjectsOfTypeAll<ShiftOrderObject>()
				where !Excluded.Contains(((Object)x).name)
				select x).ToArray();
			int twoOrderContracts = ArchipelagoHandler.Instance.slotData?.ContractCountTwo ?? 5;
			int threeOrderContracts = ArchipelagoHandler.Instance.slotData?.ContractCountThree ?? 5;
			int fourOrderContracts = ArchipelagoHandler.Instance.slotData?.ContractCountFour ?? 5;
			_cachedContracts = ContractGenerator.GenerateContracts(random, allOrders, twoOrderContracts, threeOrderContracts, fourOrderContracts);
			__result = _cachedContracts;
			return false;
		}
	}
	[HarmonyPatch(typeof(GameUtil))]
	public class GameUtil_Patches
	{
		[HarmonyPatch("InitializeGameCo")]
		[HarmonyPrefix]
		public static bool Prefix(ref IEnumerator __result)
		{
			__result = InitializeGameCo();
			return false;
		}

		private static IEnumerator InitializeGameCo()
		{
			if (!GameUtil._gameInitialized)
			{
				GameUtil._gameInitialized = true;
				yield return (object)new WaitForTask((Task)Platform.InitializeAsync());
				AggroUtil.InitializeGlobalScrobs();
				AudioManager.Initialize();
				Options.Initialize();
				if ((int)Platform.GetPlatformType() == 3)
				{
					AggroInputManager.ChangeMode((InputMode)2);
				}
			}
		}
	}
	[HarmonyPatch(typeof(LocalizedText))]
	public static class LocalizedText_Patches
	{
		[HarmonyPatch("LoadMainTable")]
		[HarmonyPostfix]
		public static void LoadMainTable(bool forceSerialization = true)
		{
			if (PluginMain.LocalizationsPath != null)
			{
				Localizer.AddCustomLocalizations(PluginMain.LocalizationsPath);
			}
		}
	}
	[HarmonyPatch(typeof(NitroController))]
	public class NitroController_Patches
	{
		[HarmonyPatch("LocalPlayerGetChargeCount")]
		[HarmonyPrefix]
		public static void OnLocalPlayerGetChargeCount(NitroController __instance)
		{
			__instance.maxNitroCharges = 1;
			if (PluginMain.SaveDataHandler?.APSaveData != null)
			{
				__instance.maxNitroCharges = PluginMain.SaveDataHandler.APSaveData.BoostUpgrades + 1;
			}
		}
	}
	[HarmonyPatch(typeof(NitroUI))]
	public class NitroUI_Patches
	{
		[HarmonyPatch("OnUpdatePresentation")]
		[HarmonyPrefix]
		public static void OnUpdatePresentation(NitroUI __instance)
		{
			if (__instance.nitroBars.Length != 5)
			{
				GameObject gameObject = ((Component)__instance.nitroBars.Last()).gameObject;
				Transform parent = gameObject.transform.parent;
				NitroBarUI component = Object.Instantiate<GameObject>(gameObject, parent).GetComponent<NitroBarUI>();
				List<NitroBarUI> list = new List<NitroBarUI>(__instance.nitroBars);
				list.Add(component);
				__instance.nitroBars = list.ToArray();
			}
		}
	}
	[HarmonyPatch(typeof(Options))]
	public static class Options_Patches
	{
		private static readonly int SERVER_SETTING_ID = AggroSettings.IdToHash("ap-server");

		private static readonly int SLOT_SETTING_ID = AggroSettings.IdToHash("ap-slot");

		private static readonly int PASS_SETTING_ID = AggroSettings.IdToHash("ap-pass");

		[HarmonyPatch("AddGameSettings")]
		[HarmonyPrefix]
		public static void AddGameSettings()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Expected O, but got Unknown
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Expected O, but got Unknown
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Expected O, but got Unknown
			AggroSettings.AddSetting("ap-server", "ap", "AP_Server", (AggroSettingBase)new TextSetting("archipelago.gg:38281", "", false));
			AggroSettings.AddSetting("ap-slot", "ap", "AP_Slot", (AggroSettingBase)new TextSetting("Player1", "", false));
			AggroSettings.AddSetting("ap-pass", "ap", "AP_Password", (AggroSettingBase)new TextSetting("", "", true));
			AggroSettings.AddSetting("ap-connect", "ap", "", (AggroSettingBase)new ButtonSetting("AP_Connect", (Action)delegate
			{
				if (ArchipelagoHandler.Instance.IsConnected)
				{
					ArchipelagoHandler.Instance.Disconnect();
				}
				else
				{
					TextSetting setting = AggroSettings.GetSetting<TextSetting>(SERVER_SETTING_ID);
					TextSetting setting2 = AggroSettings.GetSetting<TextSetting>(SLOT_SETTING_ID);
					TextSetting setting3 = AggroSettings.GetSetting<TextSetting>(PASS_SETTING_ID);
					if (!((Object)(object)ArchipelagoHandler.Instance == (Object)null) && ArchipelagoHandler.Instance.connectionFinished)
					{
						APConsole.Instance.Log("Connecting...");
						if (string.IsNullOrWhiteSpace(setting.text))
						{
							APConsole.Instance.Log("<color=\"red\">[ERROR] Server cannot be empty!</color>");
						}
						else if (string.IsNullOrWhiteSpace(setting2.text))
						{
							APConsole.Instance.Log("<color=\"red\">[ERROR] Slot cannot be empty!</color>");
						}
						else if (!ArchipelagoHandler.Instance.CreateSession(setting.text, setting2.text, setting3.text))
						{
							APConsole.Instance.Log("<color=\"red\">[ERROR] The server cannot be reached or your slot/password is incorrect.</color>");
						}
						else
						{
							ArchipelagoHandler.Instance.OnConnected += Title_Patches.HandleConnected;
							ArchipelagoHandler.Instance.OnConnectionFailed += Title_Patches.HandleConnectionFailed;
							ArchipelagoHandler.Instance.Connect();
						}
					}
				}
			}));
			AggroSettings.AddSetting("ap-debug", "ap", "AP_Debug_Logging", (AggroSettingBase)new ToggleSetting(false, (Action<bool>)delegate(bool b)
			{
				PluginMain.EnableDebugLogging = b;
			}));
			AggroSettings.AddSetting("ap-filter", "ap", "AP_Filter_Log_To_Self", (AggroSettingBase)new ToggleSetting(false, (Action<bool>)delegate(bool b)
			{
				PluginMain.FilterLog = b;
			}));
			AggroSettings.AddSetting("ap-message-in", "ap", "AP_Message_In_Time", (AggroSettingBase)new FloatSetting((Style)0, 0.15f, 0.5f, 0.25f, (Action<float>)delegate(float f)
			{
				PluginMain.MessageInTime = f;
			}, default(EventReference), default(EventReference)));
			AggroSettings.AddSetting("ap-message-hold", "ap", "AP_Message_Hold_Time", (AggroSettingBase)new FloatSetting((Style)0, 0.5f, 5f, 2.5f, (Action<float>)delegate(float f)
			{
				PluginMain.MessageHoldTime = f;
			}, default(EventReference), default(EventReference)));
			AggroSettings.AddSetting("ap-message-out", "ap", "AP_Message_Out_Time", (AggroSettingBase)new FloatSetting((Style)0, 0.15f, 0.5f, 0.4f, (Action<float>)delegate(float f)
			{
				PluginMain.MessageOutTime = f;
			}, default(EventReference), default(EventReference)));
			AggroSettings.AddSetting("ap-test-message", "ap", "", (AggroSettingBase)new ButtonSetting("AP_Test_Message", (Action)delegate
			{
				APConsole.Instance.Log("This is a test!");
			}));
		}
	}
	[HarmonyPatch(typeof(PlayerColorManager))]
	public class PlayerColorManager_Patches
	{
		[HarmonyPatch("OnEntityCreated")]
		[HarmonyPrefix]
		public static bool OnEntityCreated(PlayerColorManager __instance)
		{
			return SaveManager.isInitialized;
		}
	}
	[HarmonyPatch(typeof(PlayerCostumeManager))]
	public class PlayerCostumeManager_Patches
	{
		[HarmonyPatch("OnEntityCreated")]
		[HarmonyPrefix]
		public static bool OnEntityCreated(PlayerCostumeManager __instance)
		{
			return SaveManager.isInitialized;
		}
	}
	[HarmonyPatch(typeof(PlayerEffects))]
	public class PlayerEffects_Patches
	{
		private static readonly Dictionary<int, int> SpeedUpgradePercentage = new Dictionary<int, int>
		{
			{ 0, -10 },
			{ 1, 0 },
			{ 2, 10 },
			{ 3, 20 }
		};

		[HarmonyPatch("OnUpdateSimulationEarly")]
		[HarmonyPostfix]
		public static void OnUpdateSimulationEarly(PlayerEffects __instance)
		{
			if (PluginMain.SaveDataHandler?.APSaveData != null)
			{
				__instance.AddVehicleSpeedPercentageRaw(SpeedUpgradePercentage[PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades]);
				__instance.AddVehicleSpeedPercentageMinMax(SpeedUpgradePercentage[PluginMain.SaveDataHandler.APSaveData.SpeedUpgrades]);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerStress))]
	public class PlayerStress_Patches
	{
		[HarmonyPatch("LocalPlayerGetStressBarAmount")]
		public static bool OnLocalPlayerGetStressBarAmount(PlayerStress __instance, ref float __result)
		{
			//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)
			Entity entity = ((IEntityBehaviourBase)__instance).entity;
			PlayerUpgrades val = ((Entity)(ref entity)).GetObject<PlayerUpgrades>();
			__result = 1f;
			if (val.HasUpgrade((PlayerUpgrade)8))
			{
				__result = val.stressBarUpAmount;
			}
			__result -= 0.25f;
			if (PluginMain.SaveDataHandler?.APSaveData != null)
			{
				__result += 0.25f * (float)PluginMain.SaveDataHandler.APSaveData.StressUpgrades;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(SaveData))]
	public class SaveData_Patches
	{
		[HarmonyPatch("GetTotalBells")]
		[HarmonyPrefix]
		public static bool GetTotalBells(SaveData __instance, out int __result)
		{
			__result = PluginMain.SaveDataHandler.APSaveData?.Bells ?? 0;
			return false;
		}

		[HarmonyPatch("GetUnlockedCostumes", new Type[] { })]
		[HarmonyPrefix]
		public static bool GetUnlockedCostumes(ref CostumeObject[] __result)
		{
			__result = new List<CostumeObject>(GlobalScriptableObject<CosmeticGlobalData>.instance.costumes).ToArray();
			return false;
		}
	}
	[HarmonyPatch(typeof(SaveManager))]
	public class SaveManager_Patches
	{
		[HarmonyPatch("GetFilePath")]
		[HarmonyPrefix]
		public static bool GetFilePath(ref string __result, int saveIndex)
		{
			__result = Application.persistentDataPath + "/saves/Archipelago/" + ArchipelagoHandler.Instance.Slot + ArchipelagoHandler.Instance.Seed + ".sav";
			return false;
		}

		[HarmonyPatch("GetBackupFilePath")]
		[HarmonyPrefix]
		public static bool GetBackupFilePath(ref string __result, int saveIndex)
		{
			__result = Application.persistentDataPath + "/saves/Archipelago/" + ArchipelagoHandler.Instance.Slot + ArchipelagoHandler.Instance.Seed + "backup.sav";
			return false;
		}
	}
	[HarmonyPatch(typeof(SettingsUI))]
	public class SettingsUI_Patches
	{
		[HarmonyPatch("OpenSettings")]
		[HarmonyPrefix]
		public static bool OpenSettings(SettingsUI __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			__instance.clickCatch.SetActive(true);
			AggroInputManager.PushController((IInputController)(object)__instance);
			AggroSettings.ShowSettings("ap", __instance.settingsParent, AggroInputManager.mode);
			return false;
		}
	}
	[HarmonyPatch(typeof(ShiftManager))]
	public class ShiftManager_Patches
	{
		[HarmonyPatch("ServerTruckCompleted")]
		[HarmonyPrefix]
		public static void OnServerTruckCompleted(ShiftManager __instance)
		{
			int trucksCompleted = __instance.GetTrucksCompleted();
			int num = __instance.GetCurrentShift() - 1;
			int num2 = GameUtil.contract.bellsRequired / 5;
			APConsole.Instance.DebugLog($"Truck #{trucksCompleted + 1} | Shift #{num + 1} | Contract #{num2 + 1}");
			ArchipelagoHandler.Instance.CheckLocation(48 * num2 + 9 * num + trucksCompleted + 2);
		}

		[HarmonyPatch("TransitionShiftToShiftWon")]
		[HarmonyPrefix]
		public static void OnTransitionShiftToShiftWon(ShiftManager __instance, int seed)
		{
			int num = __instance.GetCurrentShift() - 1;
			int num2 = GameUtil.contract.bellsRequired / 5;
			APConsole.Instance.DebugLog($"Shift #{num + 1} | Contract #{num2 + 1}");
			ArchipelagoHandler.Instance.CheckLocation(48 * num2 + 9 * num + 1);
		}

		[HarmonyPatch("TransitionShiftToGameWon")]
		[HarmonyPrefix]
		public static void OnTransitionShiftToGameWon(int seed)
		{
			int num = GameUtil.contract.bellsRequired / 5;
			APConsole.Instance.DebugLog($"Shift #{5} | Contract #{num + 1}");
			ArchipelagoHandler.Instance.CheckLocation(48 * num + 36 + 1);
			SlotData? slotData = ArchipelagoHandler.Instance.slotData;
			if (num == ((slotData != null) ? new int?(slotData.ContractCount - 1) : ((int?)null)))
			{
				ArchipelagoHandler.Instance.Release();
			}
		}
	}
	[HarmonyPatch(typeof(Shop))]
	public static class Shop_Patches
	{
		[HarmonyPatch("OnEntityCreated")]
		[HarmonyPrefix]
		public static bool OnEntityCreated(Shop __instance)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (!((NetworkBehaviour)__instance).isServer || GameUtil.isTutorial)
			{
				return true;
			}
			Random random = MathUtil.GetRandom(Hash.Calculate(GameUtil.seed, Hash.Calculate(((object)__instance).GetType(), 0)));
			DeckCard<ShopItemObject>[] shopCards = GameManager_Patches.ShopCards;
			__instance._serverRandomDeck = new Deck<ShopItemObject>(((Random)(ref random)).NextInt());
			DeckCard<ShopItemObject>[] array = shopCards;
			foreach (DeckCard<ShopItemObject> val in array)
			{
				__instance._serverRandomDeck.AddCard(val.item, val.cardCount);
			}
			__instance._serverDeck = new Deck<ShopCard>(((Random)(ref random)).NextInt());
			__instance._serverDeck.AddCard(new ShopCard
			{
				type = (ItemType)1
			}, __instance._serverRandomDeck.cardCount);
			__instance._serverDeck.Shuffle();
			__instance._serverSeed = ((Random)(ref random)).NextInt();
			return false;
		}

		[HarmonyPatch("CanAddShopItem")]
		[HarmonyPrefix]
		public static bool CanAddShopItem(ShopItemObject candidate)
		{
			return PluginMain.SaveDataHandler.APSaveData?.ShopUnlocks.Contains(candidate.itemName) ?? false;
		}
	}
	[HarmonyPatch(typeof(Title))]
	public class Title_Patches
	{
		private static Button? _connectButton;

		private static Title? _instance;

		private static TextMeshProUGUI? connectTmp;

		[HarmonyPatch("Start")]
		[HarmonyPrefix]
		public static void Start(Title __instance)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			_instance = __instance;
			_connectButton = ((Component)__instance.releaseButtons[0]).GetComponent<Button>();
			((Selectable)((Component)__instance.releaseButtons[2]).GetComponent<Button>()).interactable = false;
			SettingsUI settingsUI = ((Component)((Component)_connectButton).transform.parent.parent).GetComponentInChildren<SettingsUI>();
			GameObject gameObject = ((Component)__instance.releaseButtons[1]).gameObject;
			__instance.releaseButtons = __instance.releaseButtons.Where((Button x) => ((Object)x).name != "HostGame").ToArray();
			gameObject.SetActive(false);
			Object.Destroy((Object)(object)((Component)_connectButton).GetComponentInChildren<LocalizedText>(true));
			connectTmp = ((Component)_connectButton).GetComponentInChildren<TextMeshProUGUI>(true);
			_connectButton.onClick = new ButtonClickedEvent();