Decompiled source of EasyDeliveryCoArchipelago v0.3.0

BepInEx/plugins/EasyDeliveryAP/EasyDeliveryAP.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using Archipelago.MultiClient.Net;
using Archipelago.MultiClient.Net.BounceFeatures.DeathLink;
using Archipelago.MultiClient.Net.Enums;
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.MessageLog.Messages;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EasyDeliveryAP.Archipelago;
using EasyDeliveryAP.Utils;
using EasyDeliveryAPI;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.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 Archipelago.MultiClient.Net
{
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
	internal sealed class DataStoragePropertyAttribute : Attribute
	{
		public string? SessionVariable { get; }

		public Scope Scope { get; }

		public string Key { get; }

		public DataStoragePropertyAttribute(string sessionVariable, Scope scope, string key)
		{
			//IL_0010: 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)
			SessionVariable = sessionVariable;
			Scope = scope;
			Key = key;
		}

		public DataStoragePropertyAttribute(string sessionVariable, string key)
			: this(sessionVariable, (Scope)0, key)
		{
		}
	}
}
namespace EasyDeliveryAP
{
	internal struct APSaveFile
	{
		public int handledIndex;

		public string APSeed;

		public string uri;

		public string slotName;

		public string password;

		public string modVersion;
	}
	public class APData
	{
		private static readonly ArchipelagoClient archipelago = EasyDeliveryAP.ArchipelagoClient;

		public static string payload_checks;

		public static string perfect_deliveries;

		public static string intercity_deliveries;

		public static string snowcats;

		public static string blind_bags;

		public static string lock_towns;

		public static string blocked_tunnels;

		public static string require_handheld_radio;

		public static string radio_towers;

		public static string car_upgrades;

		public static string progressive_car_upgrades;

		public static int car_trail_color;

		public static string vending_machines;

		public static string garbage_bins;

		public static string signs;

		public static Hint[] hints;

		public static void SetSlotSettings(Dictionary<string, object> slotData)
		{
			slotData.TryGetValue("payload_checks", out var value);
			payload_checks = value.ToString();
			slotData.TryGetValue("perfect_deliveries", out var value2);
			perfect_deliveries = value2.ToString();
			slotData.TryGetValue("intercity_deliveries", out var value3);
			intercity_deliveries = value3.ToString();
			slotData.TryGetValue("snowcats", out var value4);
			snowcats = value4.ToString();
			slotData.TryGetValue("blind_bags", out var value5);
			blind_bags = value5.ToString();
			slotData.TryGetValue("lock_towns", out var value6);
			lock_towns = value6.ToString();
			slotData.TryGetValue("blocked_tunnels", out var value7);
			blocked_tunnels = value7.ToString();
			slotData.TryGetValue("require_handheld_radio", out var value8);
			require_handheld_radio = value8.ToString();
			slotData.TryGetValue("radio_towers", out var value9);
			radio_towers = value9.ToString();
			slotData.TryGetValue("car_upgrades", out var value10);
			car_upgrades = value10.ToString();
			if (slotData.TryGetValue("progressive_car_upgrades", out var value11))
			{
				progressive_car_upgrades = value11.ToString();
			}
			else
			{
				progressive_car_upgrades = "0";
			}
			if (slotData.TryGetValue("randomize_trail_color", out var value12))
			{
				car_trail_color = int.Parse(value12.ToString());
			}
			else
			{
				car_trail_color = 16777215;
			}
			if (slotData.TryGetValue("vending_machines", out var value13))
			{
				vending_machines = value13.ToString();
			}
			else
			{
				vending_machines = "0";
			}
			if (slotData.TryGetValue("garbage_bins", out var value14))
			{
				garbage_bins = value14.ToString();
			}
			else
			{
				garbage_bins = "0";
			}
			if (slotData.TryGetValue("signs", out var value15))
			{
				signs = value15.ToString();
			}
			else
			{
				signs = "0";
			}
			if (intercity_deliveries == "2" || intercity_deliveries == "3")
			{
				TrackerApp.pages.Add(2);
			}
			if (payload_checks == "1")
			{
				TrackerApp.pages.Add(3);
			}
			if (snowcats == "1" || snowcats == "2")
			{
				TrackerApp.pages.Add(4);
			}
			if (blind_bags == "1")
			{
				TrackerApp.pages.Add(5);
			}
			if (radio_towers == "1" || radio_towers == "2")
			{
				TrackerApp.pages.Add(6);
			}
			if (vending_machines == "1")
			{
				TrackerApp.pages.Add(7);
			}
			if (garbage_bins == "1")
			{
				TrackerApp.pages.Add(8);
			}
			if (signs == "1")
			{
				TrackerApp.pages.Add(9);
			}
		}

		public static void SaveConnectionOrConnect()
		{
			if (ArchipelagoClient.Authenticated)
			{
				EasyDeliveryAP.save.data.uri = ArchipelagoClient.ServerData.Uri;
				EasyDeliveryAP.save.data.slotName = ArchipelagoClient.ServerData.SlotName;
				EasyDeliveryAP.save.data.password = ArchipelagoClient.ServerData.Password;
				EasyDeliveryAP.save.data.modVersion = "0.3.0";
				EasyDeliveryAP.save.data.APSeed = ArchipelagoClient.ServerData.seed;
			}
			else if (!Utility.IsNullOrWhiteSpace(EasyDeliveryAP.save.data.slotName) && EasyDeliveryAP.configAutoConnect.Value)
			{
				ArchipelagoClient.ServerData.Uri = EasyDeliveryAP.save.data.uri;
				ArchipelagoClient.ServerData.SlotName = EasyDeliveryAP.save.data.slotName;
				ArchipelagoClient.ServerData.Password = EasyDeliveryAP.save.data.password;
				archipelago.Connect();
			}
		}

		public static void OnHintsReceived(Hint[] hint)
		{
			hints = hint;
		}

		public static bool IsHinted(int locationId, bool hinted = false)
		{
			if (hinted)
			{
				return true;
			}
			Hint[] array = hints;
			foreach (Hint val in array)
			{
				if (val.FindingPlayer == archipelago.session.Players.ActivePlayer.Slot && val.LocationId == locationId)
				{
					return true;
				}
			}
			return false;
		}
	}
	public class ItemData
	{
		public string Name { get; set; }

		public int Id { get; set; }

		public int Received { get; set; }

		public bool Enabled { get; set; }

		public bool Toggle { get; set; }

		public int Given { get; set; }

		public ItemData()
		{
		}

		public ItemData(string name)
		{
			Name = name;
			Id = -1;
			Received = 0;
			Enabled = false;
			Toggle = false;
			Given = 0;
		}

		public ItemData(string name, int id)
		{
			Name = name;
			Id = id;
			Received = 0;
			Enabled = false;
			Toggle = false;
			Given = 0;
		}
	}
	public class Items
	{
		public static ItemData GPS = new ItemData("Map");

		public static ItemData Tires = new ItemData("Snow Tires");

		public static ItemData Bumper = new ItemData("Bumper");

		public static ItemData Chains = new ItemData("Ice Chains");

		public static ItemData ProgCarUpgrade = new ItemData("Progressive Car Upgrade");

		public static ItemData EnergyDrink = new ItemData("Energy Drink", 0);

		public static ItemData EmptyCan = new ItemData("Empty Can", 1);

		public static ItemData Lantern = new ItemData("Lantern", 2);

		public static ItemData Lighter = new ItemData("Lighter", 3);

		public static ItemData Firewood = new ItemData("Firewood", 4);

		public static ItemData Shovel = new ItemData("Shovel", 5);

		public static ItemData BirdSeed = new ItemData("Bird Seed", 6);

		public static ItemData CookingPot = new ItemData("Cooking Pot", 7);

		public static ItemData Coffee = new ItemData("Coffee", 8);

		public static ItemData CoffeePowder = new ItemData("Coffee Powder", 9);

		public static ItemData Tea = new ItemData("Tea", 10);

		public static ItemData TeaBags = new ItemData("Tea Bags", 11);

		public static ItemData Fish = new ItemData("Fish", 12);

		public static ItemData FishingRod = new ItemData("Fishing Rod", 13);

		public static ItemData FishSoup = new ItemData("Fish Soup", 14);

		public static ItemData DuctTape = new ItemData("Duct Tape", 15);

		public static ItemData RestoreDisc = new ItemData("Restore Disc", 16);

		public static ItemData HandheldRadio = new ItemData("Handheld Radio", 17);

		public static ItemData IceTrap = new ItemData("Ice Trap");

		public static ItemData ShrinkTrap = new ItemData("Shrink Trap");

		public static ItemData FrozenSteeringWheelTrap = new ItemData("Frozen Steering Wheel Trap");

		public static ItemData ForcedAccelerationTrap = new ItemData("Forced Acceleration Trap");

		public static ItemData TunnelSP = new ItemData("Snowy Peaks Tunnel");

		public static ItemData TunnelFT = new ItemData("Fishing Town Tunnel");

		public static ItemData TunnelFactory = new ItemData("Factory Tunnel");

		public static ItemData Upton = new ItemData("Upton");

		public static ItemData Weston = new ItemData("Weston");

		public static ItemData Easton = new ItemData("Easton");

		public static ItemData Winton = new ItemData("Winton");

		public static ItemData Munton = new ItemData("Munton");

		public static ItemData Lopton = new ItemData("Lopton");

		public static ItemData Clifton = new ItemData("Clifton");

		public static ItemData Damton = new ItemData("Damton");

		public static ItemData Smalton = new ItemData("Smalton");

		public static ItemData Money = new ItemData("Money");

		public static ItemData RadioTower = new ItemData("Radio Tower");

		public static Dictionary<int, ItemData> APIdToItem = new Dictionary<int, ItemData>
		{
			{ 1, GPS },
			{ 2, Tires },
			{ 3, Bumper },
			{ 4, Chains },
			{ 5, ProgCarUpgrade },
			{ 10, Money },
			{ 11, TunnelSP },
			{ 12, TunnelFT },
			{ 13, TunnelFactory },
			{ 20, RadioTower },
			{ 30, Upton },
			{ 31, Weston },
			{ 32, Easton },
			{ 33, Winton },
			{ 34, Munton },
			{ 35, Lopton },
			{ 36, Clifton },
			{ 37, Damton },
			{ 38, Smalton },
			{ 100, EnergyDrink },
			{ 101, EmptyCan },
			{ 102, Lantern },
			{ 103, Lighter },
			{ 104, Firewood },
			{ 105, Shovel },
			{ 106, BirdSeed },
			{ 107, CookingPot },
			{ 108, Coffee },
			{ 109, CoffeePowder },
			{ 110, Tea },
			{ 111, TeaBags },
			{ 112, Fish },
			{ 113, FishingRod },
			{ 114, FishSoup },
			{ 115, DuctTape },
			{ 116, RestoreDisc },
			{ 117, HandheldRadio },
			{ 130, IceTrap },
			{ 131, ShrinkTrap },
			{ 132, FrozenSteeringWheelTrap },
			{ 133, ForcedAccelerationTrap }
		};

		public static Dictionary<string, ItemData> NameToItem = new Dictionary<string, ItemData>
		{
			{ "Upton", Upton },
			{ "Weston", Weston },
			{ "Easton", Easton },
			{ "Winton", Winton },
			{ "Munton", Munton },
			{ "Lopton", Lopton },
			{ "Clifton", Clifton },
			{ "Damton", Damton },
			{ "Smalton", Smalton }
		};

		public static Dictionary<string, ItemData> TunnelToItem = new Dictionary<string, ItemData>
		{
			{ "Snowy Peaks", TunnelSP },
			{ "Fishing Town", TunnelFT }
		};

		public static Dictionary<string, ItemData> TownToItem = new Dictionary<string, ItemData>
		{
			{ "Upton", Upton },
			{ "Weston", Weston },
			{ "Easton", Easton },
			{ "Winton", Winton },
			{ "Munton", Munton },
			{ "Lopton", Lopton },
			{ "Clifton", Clifton },
			{ "Damton", Damton },
			{ "Smalton", Smalton }
		};
	}
	public class Locations
	{
		public class MountainTown
		{
			public static NodeData EasyFlowers = new NodeData("Easy Flowers", "Upton", 0);

			public static NodeData Node57 = new NodeData("Node (57)", "Upton", 1);

			public static NodeData Node48 = new NodeData("Node (48)", "Upton", 2);

			public static NodeData Node56 = new NodeData("Node (56)", "Upton", 3);

			public static NodeData Node55 = new NodeData("Node (55)", "Upton", 4);

			public static NodeData EasyEats = new NodeData("Easy Eats", "Upton", 5);

			public static NodeData Node47 = new NodeData("Node (47)", "Upton", 6);

			public static NodeData Node54 = new NodeData("Node (54)", "Upton", 7);

			public static NodeData Node5 = new NodeData("Node (5)", "Weston", 8);

			public static NodeData EZBakery = new NodeData("EZ Bakery", "Weston", 9);

			public static NodeData Node59 = new NodeData("Node (59)", "Weston", 10);

			public static NodeData Node60 = new NodeData("Node (60)", "Weston", 11);

			public static NodeData Bar1 = new NodeData("Bar", "Weston", 12);

			public static NodeData EasyDepot = new NodeData("Node (57)", "Weston", 13);

			public static NodeData Bar2 = new NodeData("Bar 2", "Weston", 14);

			public static NodeData EZCafe = new NodeData("EZ Cafe", "Weston", 15);

			public static NodeData Node65 = new NodeData("Node (65)", "Weston", 16);

			public static NodeData Node71 = new NodeData("Node (71)", "Easton", 17);

			public static NodeData Node72 = new NodeData("Node (72)", "Easton", 18);

			public static NodeData EasyPizza = new NodeData("Easy Pizza", "Easton", 19);

			public static NodeData Node74 = new NodeData("Node (74)", "Easton", 20);

			public static NodeData PawnShop = new NodeData("Pawn Shop", "Easton", 21);

			public static NodeData EZAuto = new NodeData("EZ Auto", "Easton", 22);

			public static NodeData EZMart = new NodeData("EZ Mart", "Easton", 23);

			public static NodeData Node92 = new NodeData("Node (92)", "Upton", 24);

			public static NodeData Node93 = new NodeData("Node (93)", "Upton", 25);

			public static PositionData VMUEats = new PositionData("VMUEats", "Upton", 100, "Vending Machine");

			public static PositionData RBUFlowers = new PositionData("RBUFlowers", "Upton", 121, "Bin");

			public static PositionData BBUFlowers = new PositionData("BBUFlowers", "Upton", 122, "Bin");

			public static PositionData BBUFlowersEats = new PositionData("BBUFlowersEats", "Upton", 123, "Bin");

			public static PositionData BBUEats = new PositionData("BBUEats", "Upton", 124, "Bin");

			public static PositionData RBUEats = new PositionData("RBUEats", "Upton", 125, "Bin");

			public static PositionData RBUTownEdge = new PositionData("RBUTownEdge", "Upton", 126, "Bin");

			public static PositionData BBWEntry = new PositionData("BBWEntry", "Weston", 127, "Bin");

			public static PositionData RBWEntry = new PositionData("RBWEntry", "Weston", 128, "Bin");

			public static PositionData BBWBakeryAcross = new PositionData("BBWBakeryAcross", "Weston", 129, "Bin");

			public static PositionData RBWBakeryLeft = new PositionData("RBWBakeryLeft", "Weston", 130, "Bin");

			public static PositionData BBWBakeryLeft = new PositionData("BBWBakeryLeft", "Weston", 131, "Bin");

			public static PositionData RBWBarTunnel = new PositionData("RBWBarTunnel", "Weston", 132, "Bin");

			public static PositionData VMWBarTunnel = new PositionData("VMWBarTunnel", "Weston", 101, "Vending Machine");

			public static PositionData BBWDepot = new PositionData("BBWDepot", "Weston", 133, "Bin");

			public static PositionData BBWBarLower = new PositionData("BBWBarLower", "Weston", 134, "Bin");

			public static PositionData RBWCafe = new PositionData("RBWCafe", "Weston", 135, "Bin");

			public static PositionData BBEMart = new PositionData("BBEMart", "Easton", 136, "Bin");

			public static PositionData RBEFuel = new PositionData("RBEFuel", "Easton", 137, "Bin");

			public static PositionData BBEFuel = new PositionData("BBEFuel", "Easton", 138, "Bin");

			public static PositionData VMEFuel = new PositionData("VMEFuel", "Easton", 102, "Vending Machine");

			public static PositionData BBEPizzaRight = new PositionData("BBEPizzaRight", "Easton", 139, "Bin");

			public static PositionData RBEPizzaLeft = new PositionData("RBEPizzaLeft", "Easton", 140, "Bin");

			public static PositionData SignToSP = new PositionData("Welcome to Mountain Town", "Upton", 200, "Sign");

			public static PositionData SignUptonExit = new PositionData("To Weston, To Easton", "Upton", 201, "Sign");

			public static PositionData SignUptonRadio = new PositionData("Upton Radio Tower", "Upton", 202, "Sign");

			public static PositionData SignWestonEntryUpton = new PositionData("Weston Upper To Upton", "Weston", 203, "Sign");

			public static PositionData SignWestonEntryEaston = new PositionData("Weston Upper To Easton", "Weston", 204, "Sign");

			public static PositionData SignFactory = new PositionData("Factory", "Weston", 205, "Sign");

			public static PositionData SignWestonExitUpton = new PositionData("Weston To Upton", "Weston", 206, "Sign");

			public static PositionData SignWestonExitEaston = new PositionData("Weston To Easton", "Weston", 207, "Sign");

			public static PositionData SignToEaston = new PositionData("Weston Bar", "Weston", 208, "Sign");

			public static PositionData SignEastonEntry = new PositionData("Weston Bridge", "Weston", 209, "Sign");

			public static PositionData SignEastonOtherEntry = new PositionData("Easton To Weston, To Upton", "Easton", 210, "Sign");

			public static PositionData SignToFTLower = new PositionData("Easton Tunnel to Fishing Town", "Easton", 211, "Sign");

			public static PositionData SignEastonExit = new PositionData("Easton", "Easton", 212, "Sign");

			public static PositionData SignToFTUpper = new PositionData("Easton Edge Tunnel to Fishing Town", "Easton", 213, "Sign");

			public static PositionData SignEastonRadio = new PositionData("Easton Radio Tower", "Easton", 214, "Sign");

			public static PositionData SignToFT = new PositionData("Easton Tunnel", "Easton", 215, "Sign");
		}

		public class SnowyPeaks
		{
			public static NodeData Destnode5 = new NodeData("Destnode5", "Lopton", 0);

			public static NodeData Destnode1 = new NodeData("Destnode1", "Lopton", 1);

			public static NodeData Destnode3 = new NodeData("Destnode3", "Lopton", 2);

			public static NodeData Destnode2 = new NodeData("Destnode2", "Lopton", 3);

			public static NodeData Destnode4 = new NodeData("Destnode4", "Lopton", 4);

			public static NodeData Destnode6 = new NodeData("Destnode6", "Lopton", 5);

			public static NodeData Destnode = new NodeData("Destnode", "Lopton", 6);

			public static NodeData Destnode10 = new NodeData("Destnode10", "Munton", 7);

			public static NodeData Destnode8 = new NodeData("Destnode8", "Lopton", 8);

			public static NodeData Destnode7 = new NodeData("Destnode7", "Lopton", 9);

			public static NodeData Destnode9 = new NodeData("Destnode9", "Winton", 10);

			public static NodeData EasyEats = new NodeData("Easy Eats", "Winton", 11);

			public static NodeData EZBakery = new NodeData("EZ Bakery", "Lopton", 12);

			public static NodeData EasyPizza = new NodeData("Easy Pizza", "Lopton", 13);

			public static NodeData EasyFlowers = new NodeData("Easy Flowers", "Winton", 14);

			public static NodeData Bar1 = new NodeData("Bar 1", "Munton", 15);

			public static NodeData EasyDepot = new NodeData("Easy Depot", "Lopton", 16);

			public static NodeData EZAuto = new NodeData("EZ Auto", "Munton", 17);

			public static NodeData EZCafe = new NodeData("EZ Cafe", "Lopton", 18);

			public static NodeData Bar2 = new NodeData("Bar 2", "Lopton", 19);

			public static NodeData EZMart = new NodeData("EZ Mart", "Munton", 20);

			public static NodeData PawnShop = new NodeData("Pawn Shop", "Munton", 21);

			public static PositionData BBWFlowers = new PositionData("BBWFlowers", "Winton", 141, "Bin");

			public static PositionData RBWEats = new PositionData("RBWEats", "Winton", 142, "Bin");

			public static PositionData VMWFuel = new PositionData("VMWFuel", "Winton", 103, "Vending Machine");

			public static PositionData BBWFuel = new PositionData("BBWFuel", "Winton", 143, "Bin");

			public static PositionData RBWFuel = new PositionData("RBWFuel", "Winton", 144, "Bin");

			public static PositionData VMMAuto = new PositionData("VMMAuto", "Munton", 104, "Vending Machine");

			public static PositionData RBMPawn = new PositionData("RBMPawn", "Munton", 145, "Bin");

			public static PositionData RBMMart = new PositionData("RBMMart", "Munton", 146, "Bin");

			public static PositionData BBMMart = new PositionData("BBMMart", "Munton", 147, "Bin");

			public static PositionData VMMBar = new PositionData("VMMBar", "Munton", 105, "Vending Machine");

			public static PositionData RBLBar = new PositionData("RBLBar", "Lopton", 148, "Bin");

			public static PositionData VMLDepot = new PositionData("VMLDepot", "Lopton", 106, "Vending Machine");

			public static PositionData RBLDepot = new PositionData("RBLDepot", "Lopton", 149, "Bin");

			public static PositionData BBLDepot = new PositionData("BBLDepot", "Lopton", 150, "Bin");

			public static PositionData SignToMT = new PositionData("Welcome to Snowy Peaks", "Winton", 216, "Sign");

			public static PositionData SignWintonExit = new PositionData("To Munton", "Winton", 217, "Sign");

			public static PositionData SignWintonEntry = new PositionData("Winton", "Winton", 218, "Sign");

			public static PositionData SignMuntonEntry = new PositionData("Munton", "Munton", 219, "Sign");

			public static PositionData SignMuntonBridgeWinton = new PositionData("To Winton", "Munton", 220, "Sign");

			public static PositionData SignMuntonBridgeLopton = new PositionData("To Lopton", "Munton", 221, "Sign");

			public static PositionData SignUpperMunton = new PositionData("Upper Munton", "Munton", 222, "Sign");

			public static PositionData SignLoptonEntry = new PositionData("Lopton", "Lopton", 223, "Sign");

			public static PositionData SignLoptonBridge = new PositionData("To Munton, To Winton", "Lopton", 224, "Sign");

			public static PositionData SignLoptonRadio = new PositionData("Snowy Peaks Radio Tower", "Lopton", 225, "Sign");
		}

		public class FishingTown
		{
			public static NodeData Node93 = new NodeData("Node (93)", "Clifton", 0);

			public static NodeData Nodedock = new NodeData("Node(dock)", "Smalton", 1);

			public static NodeData Node59 = new NodeData("Node (59)", "Damton", 2);

			public static NodeData Node101 = new NodeData("Node (101)", "Clifton", 3);

			public static NodeData Nodedock2 = new NodeData("Node (dock2)", "Smalton", 4);

			public static NodeData Node11 = new NodeData("Node (11)", "Damton", 5);

			public static NodeData Nodedock31 = new NodeData("Node (dock3) (1)", "Damton", 6);

			public static NodeData Node58 = new NodeData("Node (58)", "Damton", 7);

			public static NodeData Node91 = new NodeData("Node (91)", "Clifton", 8);

			public static NodeData Node54 = new NodeData("Node (54)", "Damton", 9);

			public static NodeData Node18 = new NodeData("Node (18)", "Damton", 10);

			public static NodeData Node64 = new NodeData("Node (64)", "Damton", 11);

			public static NodeData Node97 = new NodeData("Node (97)", "Clifton", 12);

			public static NodeData Node20 = new NodeData("Node (20)", "Damton", 13);

			public static NodeData Node22 = new NodeData("Node (22)", "Damton", 14);

			public static NodeData Node89 = new NodeData("Node (89)", "Clifton", 15);

			public static NodeData Node55 = new NodeData("Node (55)", "Damton", 16);

			public static NodeData Node112 = new NodeData("Node (112)", "Damton", 17);

			public static NodeData Node12 = new NodeData("Node (12)", "Damton", 18);

			public static NodeData Nodedock3 = new NodeData("Node (dock3)", "Damton", 19);

			public static NodeData Nodedock1 = new NodeData("Node(dock)(1)", "Smalton", 20);

			public static NodeData Node14 = new NodeData("Node (14)", "Damton", 21);

			public static NodeData Nodedock21 = new NodeData("Node (dock2) (1)", "Smalton", 22);

			public static NodeData Node102 = new NodeData("Node (102)", "Clifton", 23);

			public static NodeData Node98 = new NodeData("Node (98)", "Clifton", 24);

			public static NodeData EasyFlowers = new NodeData("Easy Flowers", "Smalton", 25);

			public static NodeData EasyEats = new NodeData("Easy Eats", "Smalton", 26);

			public static NodeData PawnShop = new NodeData("Pawn Shop", "Clifton", 27);

			public static NodeData EZMart = new NodeData("EZ Mart", "Clifton", 28);

			public static NodeData Bar2 = new NodeData("Bar", "Damton", 29);

			public static NodeData EasyDepot = new NodeData("Easy Depot", "Damton", 30);

			public static NodeData Bar1 = new NodeData("Bar", "Clifton", 31);

			public static NodeData EZCafe = new NodeData("EZ Cafe", "Damton", 32);

			public static NodeData EasyPizza = new NodeData("Easy Pizza", "Smalton", 33);

			public static NodeData EZAuto = new NodeData("EZ Auto", "Clifton", 34);

			public static NodeData EZBakery = new NodeData("EZ Bakery", "Damton", 35);

			public static PositionData RBCBar = new PositionData("RBCBar", "Clifton", 151, "Bin");

			public static PositionData BBCBar = new PositionData("BBCBar", "Clifton", 152, "Bin");

			public static PositionData VMCMart = new PositionData("VMCMart", "Clifton", 107, "Vending Machine");

			public static PositionData BBCMart = new PositionData("BBCMart", "Clifton", 153, "Bin");

			public static PositionData RBCMart = new PositionData("RBCMart", "Clifton", 154, "Bin");

			public static PositionData RBDBar = new PositionData("RBDBar", "Damton", 155, "Bin");

			public static PositionData BBDBar = new PositionData("BBDBar", "Damton", 156, "Bin");

			public static PositionData VMDBar = new PositionData("VMDBar", "Damton", 108, "Vending Machine");

			public static PositionData RBDDepot = new PositionData("RBDDepot", "Damton", 157, "Bin");

			public static PositionData BBDDepot = new PositionData("BBDDepot", "Damton", 158, "Bin");

			public static PositionData VMDDepot = new PositionData("VMDDepot", "Damton", 109, "Vending Machine");

			public static PositionData BBSPizza = new PositionData("BBSPizza", "Smalton", 159, "Bin");

			public static PositionData RBSPizza = new PositionData("RBSPizza", "Smalton", 160, "Bin");

			public static PositionData VMSEatsLeft = new PositionData("VMSEatsLeft", "Smalton", 110, "Vending Machine");

			public static PositionData VMSEatsRight = new PositionData("VMSEatsRight", "Smalton", 111, "Vending Machine");

			public static PositionData RBSEats = new PositionData("RBSEats", "Smalton", 161, "Bin");

			public static PositionData BBSEats = new PositionData("BBSEats", "Smalton", 162, "Bin");

			public static PositionData SignWelcome = new PositionData("Welcome to Fishing Town", "Clifton", 226, "Sign");

			public static PositionData SignToMT = new PositionData("Tunnel to Mountain Town", "Clifton", 227, "Sign");

			public static PositionData SignCliftonEdgeTSTD = new PositionData("To Smalton, To Damton", "Clifton", 228, "Sign");

			public static PositionData SignCliftonC = new PositionData("Clifton", "Clifton", 229, "Sign");

			public static PositionData SignCliftonToMT = new PositionData("Tunnel to Mountain Town", "Clifton", 232, "Sign");

			public static PositionData SignCliftonTSTD = new PositionData("To Smalton, To Damton", "Clifton", 233, "Sign");

			public static PositionData SignCliftonTD = new PositionData("Fork To Damton", "Clifton", 230, "Sign");

			public static PositionData SignCliftonTS = new PositionData("Fork To Smalton", "Clifton", 231, "Sign");

			public static PositionData SignLCliftonRLC = new PositionData("SignLCliftonRLC", "Clifton", 234, "Sign");

			public static PositionData SignLCliftonRTS = new PositionData("SignLCliftonRTS", "Clifton", 235, "Sign");

			public static PositionData SignLCliftonRTD = new PositionData("SignLCliftonRTD", "Clifton", 236, "Sign");

			public static PositionData SignLCliftonLTD = new PositionData("SignLCliftonLTD", "Clifton", 237, "Sign");

			public static PositionData SignLCliftonLTS = new PositionData("SignLCliftonLTS", "Clifton", 238, "Sign");

			public static PositionData SignLCliftonLLC = new PositionData("SignLCliftonLLC", "Clifton", 239, "Sign");

			public static PositionData SignSmaltonBS = new PositionData("Smalton Bridge", "Smalton", 240, "Sign");

			public static PositionData SignSmaltonTD = new PositionData("Smalton Dam", "Smalton", 241, "Sign");

			public static PositionData SignDamtonDTS = new PositionData("SignDamtonDTS", "Damton", 242, "Sign");

			public static PositionData SignDamtonDTCTS = new PositionData("SignDamtonDTCTS", "Damton", 243, "Sign");

			public static PositionData SignDamtonDLD = new PositionData("SignDamtonDLD", "Damton", 244, "Sign");

			public static PositionData SignDamtonUD = new PositionData("Upper Damton", "Damton", 245, "Sign");

			public static PositionData SignDamtonLD = new PositionData("Lower Damton", "Damton", 246, "Sign");

			public static PositionData SignDamtonD = new PositionData("SignDamtonD", "Damton", 247, "Sign");

			public static PositionData SignDamtonTCTS = new PositionData("SignDamtonTCTS", "Damton", 248, "Sign");

			public static PositionData SignDamtonTS = new PositionData("SignDamtonTS", "Damton", 249, "Sign");

			public static PositionData SignDamtonTD = new PositionData("SignDamtonTD", "Damton", 250, "Sign");
		}

		public static readonly Dictionary<string, int> Town = new Dictionary<string, int>
		{
			{ "Upton", 11 },
			{ "Weston", 12 },
			{ "Easton", 13 },
			{ "Winton", 21 },
			{ "Munton", 22 },
			{ "Lopton", 23 },
			{ "Clifton", 31 },
			{ "Damton", 32 },
			{ "Smalton", 33 }
		};

		public static readonly Dictionary<string, int> City = new Dictionary<string, int>
		{
			{ "Mountain Town", 10 },
			{ "Snowy Peaks", 20 },
			{ "Fishing Town", 30 }
		};

		public static Dictionary<string, int> Deliveries = GetDeliveries();

		public static readonly Dictionary<string, int> PayloadDeliveries = new Dictionary<string, int>
		{
			{ "PAYLOAD Big Box", 1 },
			{ "PAYLOAD BixBoxStack", 2 },
			{ "PAYLOAD BoxBunch", 3 },
			{ "PAYLOAD BoxStack", 4 },
			{ "PAYLOAD Crate", 5 },
			{ "PAYLOAD CrateOfDrinks", 6 },
			{ "PAYLOAD CrateStack", 7 },
			{ "PAYLOAD LotsOfCratesOfDrinks", 8 },
			{ "PAYLOAD PizzaStack", 9 },
			{ "PAYLOAD PizzaStackMega", 10 },
			{ "PAYLOAD PlantPot", 11 },
			{ "PAYLOAD PlantPotBunch", 12 },
			{ "PAYLOAD PlantPotStack", 13 },
			{ "PAYLOAD PlantPotWide", 14 },
			{ "PAYLOAD Sack", 15 },
			{ "PAYLOAD SackStack", 16 },
			{ "Drink", 17 }
		};

		public static readonly Dictionary<string, int> BlindBags = new Dictionary<string, int>
		{
			{ "1Blind Bag", 20 },
			{ "1Blind Bag (1)", 21 },
			{ "1Blind Bag (2)", 22 },
			{ "1Blind Bag (3)", 23 },
			{ "5Blind Bag", 24 },
			{ "5Blind Bag (1)", 25 },
			{ "5Blind Bag (2)", 26 },
			{ "5Blind Bag (3)", 27 },
			{ "4Blind Bag", 28 },
			{ "4Blind Bag (1)", 29 },
			{ "4Blind Bag (2)", 30 },
			{ "4Blind Bag (3)", 31 }
		};

		public static readonly Dictionary<string, NodeData> MountainTownNode = new Dictionary<string, NodeData>
		{
			{
				"Easy Flowers",
				MountainTown.EasyFlowers
			},
			{
				"Node (57)",
				MountainTown.Node57
			},
			{
				"Node (48)",
				MountainTown.Node48
			},
			{
				"Node (56)",
				MountainTown.Node56
			},
			{
				"Node (55)",
				MountainTown.Node55
			},
			{
				"Easy Eats",
				MountainTown.EasyEats
			},
			{
				"Node (47)",
				MountainTown.Node47
			},
			{
				"Node (54)",
				MountainTown.Node54
			},
			{
				"Node (5)",
				MountainTown.Node5
			},
			{
				"EZ Bakery",
				MountainTown.EZBakery
			},
			{
				"Node (59)",
				MountainTown.Node59
			},
			{
				"Node (60)",
				MountainTown.Node60
			},
			{
				"Bar 1",
				MountainTown.Bar1
			},
			{
				"Easy Depot",
				MountainTown.EasyDepot
			},
			{
				"Bar 2",
				MountainTown.Bar2
			},
			{
				"EZ Cafe",
				MountainTown.EZCafe
			},
			{
				"Node (65)",
				MountainTown.Node65
			},
			{
				"Node (71)",
				MountainTown.Node71
			},
			{
				"Node (72)",
				MountainTown.Node72
			},
			{
				"Easy Pizza",
				MountainTown.EasyPizza
			},
			{
				"Node (74)",
				MountainTown.Node74
			},
			{
				"Pawn Shop",
				MountainTown.PawnShop
			},
			{
				"EZ Auto",
				MountainTown.EZAuto
			},
			{
				"EZ Mart",
				MountainTown.EZMart
			},
			{
				"Node (92)",
				MountainTown.Node92
			},
			{
				"Node (93)",
				MountainTown.Node93
			}
		};

		public static readonly Dictionary<int, NodeData> MountainTownIndex = new Dictionary<int, NodeData>
		{
			{
				0,
				MountainTown.EasyFlowers
			},
			{
				1,
				MountainTown.Node57
			},
			{
				2,
				MountainTown.Node48
			},
			{
				3,
				MountainTown.Node56
			},
			{
				4,
				MountainTown.Node55
			},
			{
				5,
				MountainTown.EasyEats
			},
			{
				6,
				MountainTown.Node47
			},
			{
				7,
				MountainTown.Node54
			},
			{
				8,
				MountainTown.Node5
			},
			{
				9,
				MountainTown.EZBakery
			},
			{
				10,
				MountainTown.Node59
			},
			{
				11,
				MountainTown.Node60
			},
			{
				12,
				MountainTown.Bar1
			},
			{
				13,
				MountainTown.EasyDepot
			},
			{
				14,
				MountainTown.Bar2
			},
			{
				15,
				MountainTown.EZCafe
			},
			{
				16,
				MountainTown.Node65
			},
			{
				17,
				MountainTown.Node71
			},
			{
				18,
				MountainTown.Node72
			},
			{
				19,
				MountainTown.EasyPizza
			},
			{
				20,
				MountainTown.Node74
			},
			{
				21,
				MountainTown.PawnShop
			},
			{
				22,
				MountainTown.EZAuto
			},
			{
				23,
				MountainTown.EZMart
			},
			{
				24,
				MountainTown.Node92
			},
			{
				25,
				MountainTown.Node93
			}
		};

		public static readonly Dictionary<string, NodeData> SnowyPeaksNode = new Dictionary<string, NodeData>
		{
			{
				"Destnode5",
				SnowyPeaks.Destnode5
			},
			{
				"Destnode1",
				SnowyPeaks.Destnode1
			},
			{
				"Destnode3",
				SnowyPeaks.Destnode3
			},
			{
				"Destnode2",
				SnowyPeaks.Destnode2
			},
			{
				"Destnode4",
				SnowyPeaks.Destnode4
			},
			{
				"Destnode6",
				SnowyPeaks.Destnode6
			},
			{
				"Destnode",
				SnowyPeaks.Destnode
			},
			{
				"Destnode10",
				SnowyPeaks.Destnode10
			},
			{
				"Destnode8",
				SnowyPeaks.Destnode8
			},
			{
				"Destnode7",
				SnowyPeaks.Destnode7
			},
			{
				"Destnode9",
				SnowyPeaks.Destnode9
			},
			{
				"Easy Eats",
				SnowyPeaks.EasyEats
			},
			{
				"EZ Bakery",
				SnowyPeaks.EZBakery
			},
			{
				"Easy Pizza",
				SnowyPeaks.EasyPizza
			},
			{
				"Easy Flowers",
				SnowyPeaks.EasyFlowers
			},
			{
				"Bar 1",
				SnowyPeaks.Bar1
			},
			{
				"Easy Depot",
				SnowyPeaks.EasyDepot
			},
			{
				"EZ Auto",
				SnowyPeaks.EZAuto
			},
			{
				"EZ Cafe",
				SnowyPeaks.EZCafe
			},
			{
				"Bar 2",
				SnowyPeaks.Bar2
			},
			{
				"EZ Mart",
				SnowyPeaks.EZMart
			},
			{
				"Pawn Shop",
				SnowyPeaks.PawnShop
			}
		};

		public static readonly Dictionary<int, NodeData> SnowyPeaksIndex = new Dictionary<int, NodeData>
		{
			{
				0,
				SnowyPeaks.Destnode5
			},
			{
				1,
				SnowyPeaks.Destnode1
			},
			{
				2,
				SnowyPeaks.Destnode3
			},
			{
				3,
				SnowyPeaks.Destnode2
			},
			{
				4,
				SnowyPeaks.Destnode4
			},
			{
				5,
				SnowyPeaks.Destnode6
			},
			{
				6,
				SnowyPeaks.Destnode
			},
			{
				7,
				SnowyPeaks.Destnode10
			},
			{
				8,
				SnowyPeaks.Destnode8
			},
			{
				9,
				SnowyPeaks.Destnode7
			},
			{
				10,
				SnowyPeaks.Destnode9
			},
			{
				11,
				SnowyPeaks.EasyEats
			},
			{
				12,
				SnowyPeaks.EZBakery
			},
			{
				13,
				SnowyPeaks.EasyPizza
			},
			{
				14,
				SnowyPeaks.EasyFlowers
			},
			{
				15,
				SnowyPeaks.Bar1
			},
			{
				16,
				SnowyPeaks.EasyDepot
			},
			{
				17,
				SnowyPeaks.EZAuto
			},
			{
				18,
				SnowyPeaks.EZCafe
			},
			{
				19,
				SnowyPeaks.Bar2
			},
			{
				20,
				SnowyPeaks.EZMart
			},
			{
				21,
				SnowyPeaks.PawnShop
			}
		};

		public static readonly Dictionary<string, NodeData> FishingTownNode = new Dictionary<string, NodeData>
		{
			{
				"Node93",
				FishingTown.Node93
			},
			{
				"Nodedock",
				FishingTown.Nodedock
			},
			{
				"Node59",
				FishingTown.Node59
			},
			{
				"Node101",
				FishingTown.Node101
			},
			{
				"Nodedock2",
				FishingTown.Nodedock2
			},
			{
				"Node11",
				FishingTown.Node11
			},
			{
				"Nodedock31",
				FishingTown.Nodedock31
			},
			{
				"Node58",
				FishingTown.Node58
			},
			{
				"Node91",
				FishingTown.Node91
			},
			{
				"Node54",
				FishingTown.Node54
			},
			{
				"Node18",
				FishingTown.Node18
			},
			{
				"Node64",
				FishingTown.Node64
			},
			{
				"Node97",
				FishingTown.Node97
			},
			{
				"Node20",
				FishingTown.Node20
			},
			{
				"Node22",
				FishingTown.Node22
			},
			{
				"Node89",
				FishingTown.Node89
			},
			{
				"Node55",
				FishingTown.Node55
			},
			{
				"Node112",
				FishingTown.Node112
			},
			{
				"Node12",
				FishingTown.Node12
			},
			{
				"Nodedock3",
				FishingTown.Nodedock3
			},
			{
				"Nodedock1",
				FishingTown.Nodedock1
			},
			{
				"Node14",
				FishingTown.Node14
			},
			{
				"Nodedock21",
				FishingTown.Nodedock21
			},
			{
				"Node102",
				FishingTown.Node102
			},
			{
				"Node98",
				FishingTown.Node98
			},
			{
				"EasyFlowers",
				FishingTown.EasyFlowers
			},
			{
				"EasyEats",
				FishingTown.EasyEats
			},
			{
				"PawnShop",
				FishingTown.PawnShop
			},
			{
				"EZMart",
				FishingTown.EZMart
			},
			{
				"Bar2",
				FishingTown.Bar2
			},
			{
				"EasyDepot",
				FishingTown.EasyDepot
			},
			{
				"Bar1",
				FishingTown.Bar1
			},
			{
				"EZCafe",
				FishingTown.EZCafe
			},
			{
				"EasyPizza",
				FishingTown.EasyPizza
			},
			{
				"EZAuto",
				FishingTown.EZAuto
			},
			{
				"EZBakery",
				FishingTown.EZBakery
			}
		};

		public static readonly Dictionary<int, NodeData> FishingTownIndex = new Dictionary<int, NodeData>
		{
			{
				0,
				FishingTown.Node93
			},
			{
				1,
				FishingTown.Nodedock
			},
			{
				2,
				FishingTown.Node59
			},
			{
				3,
				FishingTown.Node101
			},
			{
				4,
				FishingTown.Nodedock2
			},
			{
				5,
				FishingTown.Node11
			},
			{
				6,
				FishingTown.Nodedock31
			},
			{
				7,
				FishingTown.Node58
			},
			{
				8,
				FishingTown.Node91
			},
			{
				9,
				FishingTown.Node54
			},
			{
				10,
				FishingTown.Node18
			},
			{
				11,
				FishingTown.Node64
			},
			{
				12,
				FishingTown.Node97
			},
			{
				13,
				FishingTown.Node20
			},
			{
				14,
				FishingTown.Node22
			},
			{
				15,
				FishingTown.Node89
			},
			{
				16,
				FishingTown.Node55
			},
			{
				17,
				FishingTown.Node112
			},
			{
				18,
				FishingTown.Node12
			},
			{
				19,
				FishingTown.Nodedock3
			},
			{
				20,
				FishingTown.Nodedock1
			},
			{
				21,
				FishingTown.Node14
			},
			{
				22,
				FishingTown.Nodedock21
			},
			{
				23,
				FishingTown.Node102
			},
			{
				24,
				FishingTown.Node98
			},
			{
				25,
				FishingTown.EasyFlowers
			},
			{
				26,
				FishingTown.EasyEats
			},
			{
				27,
				FishingTown.PawnShop
			},
			{
				28,
				FishingTown.EZMart
			},
			{
				29,
				FishingTown.Bar2
			},
			{
				30,
				FishingTown.EasyDepot
			},
			{
				31,
				FishingTown.Bar1
			},
			{
				32,
				FishingTown.EZCafe
			},
			{
				33,
				FishingTown.EasyPizza
			},
			{
				34,
				FishingTown.EZAuto
			},
			{
				35,
				FishingTown.EZBakery
			}
		};

		public static readonly Dictionary<string, PositionData> MountainTownPositions = new Dictionary<string, PositionData>
		{
			{
				"(-323.89, 326.97, -278.76)",
				MountainTown.VMUEats
			},
			{
				"(-379.38, 326.80, -291.69)",
				MountainTown.RBUFlowers
			},
			{
				"(-378.53, 326.80, -290.91)",
				MountainTown.BBUFlowers
			},
			{
				"(-355.97, 326.82, -288.83)",
				MountainTown.BBUFlowersEats
			},
			{
				"(-326.58, 326.80, -279.27)",
				MountainTown.BBUEats
			},
			{
				"(-325.83, 326.79, -279.25)",
				MountainTown.RBUEats
			},
			{
				"(-267.40, 328.12, -278.91)",
				MountainTown.RBUTownEdge
			},
			{
				"(287.45, 198.50, -49.99)",
				MountainTown.BBWEntry
			},
			{
				"(320.60, 198.86, -65.65)",
				MountainTown.RBWEntry
			},
			{
				"(407.72, 196.02, -72.15)",
				MountainTown.BBWBakeryAcross
			},
			{
				"(436.57, 195.03, -84.92)",
				MountainTown.RBWBakeryLeft
			},
			{
				"(435.85, 195.05, -84.81)",
				MountainTown.BBWBakeryLeft
			},
			{
				"(457.49, 195.15, -50.03)",
				MountainTown.RBWBarTunnel
			},
			{
				"(446.47, 195.79, -43.11)",
				MountainTown.VMWBarTunnel
			},
			{
				"(398.14, 195.00, -37.17)",
				MountainTown.BBWDepot
			},
			{
				"(279.93, 156.83, 69.52)",
				MountainTown.BBWBarLower
			},
			{
				"(230.71, 156.11, 68.35)",
				MountainTown.RBWCafe
			},
			{
				"(-208.38, 146.34, 42.44)",
				MountainTown.BBEMart
			},
			{
				"(-143.60, 146.19, 38.97)",
				MountainTown.RBEFuel
			},
			{
				"(-144.36, 146.22, 39.11)",
				MountainTown.BBEFuel
			},
			{
				"(-140.00, 146.32, 37.85)",
				MountainTown.VMEFuel
			},
			{
				"(-202.84, 146.27, 26.13)",
				MountainTown.BBEPizzaRight
			},
			{
				"(-139.48, 146.15, 6.84)",
				MountainTown.RBEPizzaLeft
			},
			{
				"(-445.35, 329.58, -305.98)",
				MountainTown.SignToSP
			},
			{
				"(-192.70, 331.69, -251.75)",
				MountainTown.SignUptonExit
			},
			{
				"(385.50, 352.25, -244.08)",
				MountainTown.SignUptonRadio
			},
			{
				"(262.00, 199.57, -67.52)",
				MountainTown.SignWestonEntryUpton
			},
			{
				"(269.42, 200.02, -45.38)",
				MountainTown.SignWestonEntryEaston
			},
			{
				"(486.47, 195.85, -61.77)",
				MountainTown.SignFactory
			},
			{
				"(374.95, 164.78, 35.62)",
				MountainTown.SignWestonExitUpton
			},
			{
				"(373.63, 163.87, 47.30)",
				MountainTown.SignWestonExitEaston
			},
			{
				"(274.21, 159.25, 84.87)",
				MountainTown.SignToEaston
			},
			{
				"(126.83, 152.05, 41.89)",
				MountainTown.SignEastonEntry
			},
			{
				"(-33.76, 142.62, 62.99)",
				MountainTown.SignEastonOtherEntry
			},
			{
				"(-45.99, 142.62, 70.29)",
				MountainTown.SignToFTLower
			},
			{
				"(-58.33, 142.32, 54.48)",
				MountainTown.SignEastonExit
			},
			{
				"(-382.42, 146.43, 39.41)",
				MountainTown.SignToFTUpper
			},
			{
				"(-436.95, 140.38, 35.60)",
				MountainTown.SignEastonRadio
			},
			{
				"(-495.71, 126.33, 140.12)",
				MountainTown.SignToFT
			}
		};

		public static readonly Dictionary<string, PositionData> SnowyPeaksPositions = new Dictionary<string, PositionData>
		{
			{
				"(-279.34, 277.75, 233.77)",
				SnowyPeaks.BBWFlowers
			},
			{
				"(-288.79, 277.53, 232.49)",
				SnowyPeaks.RBWEats
			},
			{
				"(-325.92, 277.63, 209.57)",
				SnowyPeaks.VMWFuel
			},
			{
				"(-323.14, 277.39, 212.76)",
				SnowyPeaks.BBWFuel
			},
			{
				"(-322.31, 277.42, 213.12)",
				SnowyPeaks.RBWFuel
			},
			{
				"(120.29, 243.89, 252.13)",
				SnowyPeaks.VMMAuto
			},
			{
				"(111.71, 243.84, 222.27)",
				SnowyPeaks.RBMPawn
			},
			{
				"(256.12, 331.05, 261.82)",
				SnowyPeaks.BBMMart
			},
			{
				"(255.40, 331.02, 262.43)",
				SnowyPeaks.RBMMart
			},
			{
				"(273.01, 330.99, 243.18)",
				SnowyPeaks.VMMBar
			},
			{
				"(307.56, 277.49, -382.80)",
				SnowyPeaks.RBLBar
			},
			{
				"(233.84, 277.28, -440.07)",
				SnowyPeaks.VMLDepot
			},
			{
				"(227.77, 277.29, -439.43)",
				SnowyPeaks.RBLDepot
			},
			{
				"(228.23, 277.29, -438.71)",
				SnowyPeaks.BBLDepot
			},
			{
				"(-156.92, 245.51, 272.73)",
				SnowyPeaks.SignToMT
			},
			{
				"(-139.71, 245.77, 249.59)",
				SnowyPeaks.SignWintonExit
			},
			{
				"(-153.33, 246.28, 247.21)",
				SnowyPeaks.SignWintonEntry
			},
			{
				"(81.62, 246.57, 221.57)",
				SnowyPeaks.SignMuntonEntry
			},
			{
				"(335.00, 245.57, 124.35)",
				SnowyPeaks.SignMuntonBridgeWinton
			},
			{
				"(335.29, 246.03, 105.27)",
				SnowyPeaks.SignMuntonBridgeLopton
			},
			{
				"(360.68, 246.47, 125.37)",
				SnowyPeaks.SignUpperMunton
			},
			{
				"(353.74, 248.13, -214.54)",
				SnowyPeaks.SignLoptonEntry
			},
			{
				"(-331.79, 246.64, -266.31)",
				SnowyPeaks.SignLoptonBridge
			},
			{
				"(-320.11, 247.85, -247.79)",
				SnowyPeaks.SignLoptonRadio
			}
		};

		public static readonly Dictionary<string, PositionData> FishingTownPositions = new Dictionary<string, PositionData>
		{
			{
				"(234.21, 92.07, 289.82)",
				FishingTown.RBCBar
			},
			{
				"(233.87, 92.06, 288.78)",
				FishingTown.BBCBar
			},
			{
				"(278.26, 92.31, 313.60)",
				FishingTown.VMCMart
			},
			{
				"(288.85, 92.32, 316.12)",
				FishingTown.BBCMart
			},
			{
				"(287.93, 92.33, 316.15)",
				FishingTown.RBCMart
			},
			{
				"(416.86, 74.57, -364.26)",
				FishingTown.RBDBar
			},
			{
				"(417.68, 74.57, -364.23)",
				FishingTown.BBDBar
			},
			{
				"(414.58, 74.61, -364.05)",
				FishingTown.VMDBar
			},
			{
				"(211.42, 36.28, -474.88)",
				FishingTown.RBDDepot
			},
			{
				"(212.23, 36.32, -474.92)",
				FishingTown.BBDDepot
			},
			{
				"(207.45, 36.32, -474.97)",
				FishingTown.VMDDepot
			},
			{
				"(-198.02, 25.32, -497.58)",
				FishingTown.BBSPizza
			},
			{
				"(-198.83, 25.32, -497.60)",
				FishingTown.RBSPizza
			},
			{
				"(-410.32, 76.99, -430.47)",
				FishingTown.VMSEatsLeft
			},
			{
				"(-412.82, 76.99, -430.47)",
				FishingTown.VMSEatsRight
			},
			{
				"(-407.54, 76.87, -430.97)",
				FishingTown.RBSEats
			},
			{
				"(-408.35, 76.87, -430.94)",
				FishingTown.BBSEats
			},
			{
				"(-426.09, 125.57, 201.99)",
				FishingTown.SignWelcome
			},
			{
				"(-6.70, 82.43, 351.96)",
				FishingTown.SignToMT
			},
			{
				"(-2.87, 80.72, 337.14)",
				FishingTown.SignCliftonEdgeTSTD
			},
			{
				"(19.71, 81.17, 342.55)",
				FishingTown.SignCliftonC
			},
			{
				"(89.07, 92.61, 335.14)",
				FishingTown.SignCliftonToMT
			},
			{
				"(87.40, 93.06, 313.40)",
				FishingTown.SignCliftonTSTD
			},
			{
				"(-10.98, 68.86, 282.54)",
				FishingTown.SignCliftonTD
			},
			{
				"(-25.19, 67.54, 285.79)",
				FishingTown.SignCliftonTS
			},
			{
				"(-14.93, 33.02, 195.51)",
				FishingTown.SignLCliftonRLC
			},
			{
				"(-14.25, 32.98, 176.99)",
				FishingTown.SignLCliftonRTS
			},
			{
				"(2.11, 33.39, 178.20)",
				FishingTown.SignLCliftonRTD
			},
			{
				"(238.04, 35.06, 102.83)",
				FishingTown.SignLCliftonLTD
			},
			{
				"(231.32, 34.65, 117.80)",
				FishingTown.SignLCliftonLTS
			},
			{
				"(249.88, 34.85, 123.69)",
				FishingTown.SignLCliftonLLC
			},
			{
				"(-398.06, 45.30, -128.26)",
				FishingTown.SignSmaltonBS
			},
			{
				"(-136.70, 26.10, -484.49)",
				FishingTown.SignSmaltonTD
			},
			{
				"(93.58, 36.67, -444.48)",
				FishingTown.SignDamtonDTS
			},
			{
				"(100.39, 36.67, -432.55)",
				FishingTown.SignDamtonDTCTS
			},
			{
				"(115.01, 37.37, -439.39)",
				FishingTown.SignDamtonDLD
			},
			{
				"(254.17, 39.26, -376.64)",
				FishingTown.SignDamtonUD
			},
			{
				"(419.08, 76.57, -193.78)",
				FishingTown.SignDamtonLD
			},
			{
				"(162.18, 31.89, -353.16)",
				FishingTown.SignDamtonD
			},
			{
				"(155.50, 31.61, -335.05)",
				FishingTown.SignDamtonTCTS
			},
			{
				"(141.19, 32.72, -339.13)",
				FishingTown.SignDamtonTS
			},
			{
				"(351.96, 43.82, -138.48)",
				FishingTown.SignDamtonTD
			}
		};

		private static Dictionary<string, int> GetDeliveries()
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (KeyValuePair<string, int> item in Town)
			{
				foreach (KeyValuePair<string, int> item2 in Town)
				{
					dictionary.Add(item.Key + " to " + item2.Key + " Delivery", int.Parse($"{item.Value}{item2.Value}"));
				}
			}
			foreach (KeyValuePair<string, int> item3 in City)
			{
				foreach (KeyValuePair<string, int> item4 in City)
				{
					dictionary.Add(item3.Key + " to " + item4.Key + " Delivery", int.Parse($"{item3.Value}{item4.Value}"));
				}
			}
			return dictionary;
		}
	}
	public class NodeData
	{
		public string Name { get; set; }

		public string Town { get; set; }

		public int Index { get; set; }

		public NodeData()
		{
		}

		public NodeData(string name, string town, int index)
		{
			Name = name;
			Town = town;
			Index = index;
		}
	}
	public class PositionData
	{
		public string Name { get; set; }

		public string Town { get; set; }

		public string Type { get; set; }

		public int LocationId { get; set; }

		public PositionData(string name, string town, int locId)
		{
			Name = name;
			Town = town;
			LocationId = locId;
			Type = "None";
		}

		public PositionData(string name, string town, int locId, string type)
		{
			Name = name;
			Town = town;
			LocationId = locId;
			Type = type;
		}
	}
	public class TestData
	{
		public static bool optionStartMap = true;
	}
	[HarmonyPatch]
	public class APJobGenerator
	{
		[HarmonyPatch(typeof(jobBoard), "GenerateJobBetter")]
		private static bool Prefix(int __0, jobBoard __instance, ref Job __result)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0498: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Expected O, but got Unknown
			if (!ArchipelagoClient.Authenticated && !EasyDeliveryAP.debug)
			{
				__result = null;
				return false;
			}
			List<Transform> list = new List<Transform>();
			for (int i = 0; i < __instance.navigation.towns.Length; i++)
			{
				if (((Component)__instance.navigation.towns[i]).gameObject.activeSelf && (APData.lock_towns != "1" || Items.TownToItem[((Object)__instance.navigation.towns[i]).name].Received >= 1))
				{
					list.Add(__instance.navigation.towns[i]);
				}
			}
			if (list.Count == 0)
			{
				__result = null;
				return false;
			}
			int num = -1;
			for (int j = 0; j < list.Count; j++)
			{
				if (num == -1)
				{
					num = j;
				}
				float num2 = Vector3.Distance(list[j].position, ((Component)__instance.navigation.car).transform.position);
				float num3 = Vector3.Distance(list[num].position, ((Component)__instance.navigation.car).transform.position);
				if (num2 < num3)
				{
					num = j;
				}
			}
			Transform val = list[0];
			Transform val2 = list[0];
			if (list.Count == 2 || __instance.intercityJobs)
			{
				int index = Random.Range(0, list.Count);
				int index2 = Random.Range(0, list.Count);
				val = list[index];
				val2 = list[index2];
			}
			else if (list.Count >= 3)
			{
				switch (__0)
				{
				case 0:
					val = list[num];
					val2 = list[num];
					break;
				case 1:
					val = list[num];
					val2 = list[(num + 1) % list.Count];
					break;
				case 2:
					val = list[num];
					val2 = list[(num + 2) % list.Count];
					break;
				case 3:
					val = list[(num + 1) % list.Count];
					val2 = list[(num + 2) % list.Count];
					break;
				case 4:
					val = list[(num + 2) % list.Count];
					val2 = list[(num + 1) % list.Count];
					break;
				}
			}
			int num4 = 10000;
			ShopInfo val3;
			do
			{
				val3 = __instance.navigation.shopNodes[Random.Range(0, __instance.navigation.shopNodes.Count)];
				num4--;
			}
			while (num4 >= 0 && (Object)(object)val3.node.town != (Object)(object)val);
			TunnelNode val4 = null;
			int destinationIndex = -1;
			num4 = 10000;
			sMapNode val5;
			if (!__instance.intercityJobs)
			{
				while (true)
				{
					int num5 = Random.Range(0, __instance.navigation.destinationNodes.Count);
					val5 = __instance.navigation.destinationNodes[num5];
					num4--;
					if (num4 < 0)
					{
						break;
					}
					if (!((Object)(object)val5 == (Object)(object)val3.node) && (__instance.sameTownDeliveries || !((Object)(object)val5.town == (Object)(object)val3.node.town)) && list.Contains(val5.town) && !((Object)(object)val5.town != (Object)(object)val2))
					{
						destinationIndex = num5;
						ArchipelagoConsole.LogMessage(((Object)val5).name);
						break;
					}
				}
			}
			else
			{
				val4 = __instance.tunnelNodes[Random.Range(0, __instance.tunnelNodes.Length)];
				string name = ((Object)val4.node).name;
				if (!__instance.navigation.nodes.Contains(val4.node) || ((name == "Snowy Peaks" || ScenePatches.currentScene == "Snowy Peaks") && !APLogic.CanReachSnowyPeaks()) || ((name == "Fishing Town" || ScenePatches.currentScene == "Fishing Town") && (!APLogic.CanReachFishingTown() || !APLogic.FTGateIsOpen())))
				{
					__result = null;
					return false;
				}
				val5 = val4.node;
			}
			Job val6 = new Job(val3, val5);
			val6.path = __instance.navigation.FindPath(val6.from, val6.to);
			val6.distance = sPathFinder.PathLength(val6.path) / 1000f;
			val6.startingCityName = __instance.cityName;
			val6.destCityName = __instance.cityName;
			val6.destinationIndex = destinationIndex;
			val6.bonusDistance = 0f;
			if (Object.op_Implicit((Object)(object)val4))
			{
				int num6 = Random.Range(0, val4.distances.Length);
				while (val4.distances[num6] >= val4.distanceCutoff)
				{
					num6 = Random.Range(0, val4.distances.Length);
				}
				if (APData.lock_towns == "1")
				{
					switch (((Object)val4.node).name)
					{
					case "Mountain Town":
						if (Items.TownToItem[Locations.MountainTownIndex[num6].Town].Received < 1)
						{
							__result = null;
							return false;
						}
						break;
					case "Snowy Peaks":
						if (Items.TownToItem[Locations.SnowyPeaksIndex[num6].Town].Received < 1)
						{
							__result = null;
							return false;
						}
						break;
					case "Fishing Town":
						if (Items.TownToItem[Locations.FishingTownIndex[num6].Town].Received < 1)
						{
							__result = null;
							return false;
						}
						break;
					}
				}
				val6.destinationIndex = num6;
				val6.destCityName = ((Object)val4).name;
				val6.distance += (val4.distances[num6] + val4.distanceToOtherTown) / 1000f;
				val6.bonusDistance = sPathFinder.PathLength(__instance.navigation.FindPath(__instance.navigation.currentClosestNode, val4.node)) / 1000f;
				val6.isIntercity = true;
			}
			else
			{
				val6.bonusDistance = sPathFinder.PathLength(__instance.navigation.FindPath(__instance.navigation.currentClosestNode, val6.shop.node)) / 1000f;
			}
			val6.price = __instance.JobPrice(val6, val6.bonusDistance);
			__result = val6;
			return false;
		}
	}
	[HarmonyPatch]
	public class CarPatches
	{
		private static readonly ArchipelagoClient archipelago = EasyDeliveryAP.ArchipelagoClient;

		public static bool shrink = false;

		private static Vector3 shrinkSpeed = new Vector3(0.01f, 0.01f, 0.01f);

		private static int shrinkTimer = 0;

		public static bool iceTrap = false;

		private static int iceTimer = 0;

		public static bool teleport = false;

		private static Vector3 MountainTownTP = new Vector3(-452.94f, 328f, -325.21f);

		private static Quaternion MountainTownQt = new Quaternion(0.00282f, 0.45403f, -0.00174f, 0.89098f);

		private static Vector3 SnowyPeaksTP = new Vector3(-350.28f, 288f, 388.1f);

		private static Quaternion SnowyPeaksQt = new Quaternion(0.00282f, 0.45403f, -0.00174f, 0.89098f);

		private static Vector3 FishingTownTP = new Vector3(-471.51f, 124.16f, 193.76f);

		private static Quaternion FishingTownQt = new Quaternion(-0.00178f, 0.75104f, -0.00163f, -0.66025f);

		public static Color trailColor = new Color(1f, 1f, 1f);

		public static bool turnTrap = false;

		private static int turnTimer = 0;

		private static float randomTurn = 0f;

		public static bool accelTrap = false;

		private static int accelTimer = 0;

		public static bool debugTP = false;

		public static Vector3 debugTPDest;

		[HarmonyPatch(typeof(sCarController), "Update")]
		private static void Prefix(sCarController __instance)
		{
			//IL_002f: 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_00fb: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			if (!PauseSystem.paused && !__instance.guyActive)
			{
				if (shrink)
				{
					if (((Component)__instance).transform.localScale.x > 1f)
					{
						Transform transform = ((Component)__instance).transform;
						transform.localScale -= shrinkSpeed;
						Transform payloadPivot = __instance.payloadPivot;
						payloadPivot.localScale -= shrinkSpeed;
						__instance.maxDrivePower -= 4f;
						__instance.maxSpeed -= 2f / 3f;
						__instance.maxSpeedScale -= 1f / 150f;
						__instance.drivePowerScale -= 1f / 150f;
					}
					else
					{
						shrink = false;
						shrinkTimer += 1800;
						((Component)OtherPatches.guy).transform.localScale = new Vector3(0.75f, 0.75f, 0.75f);
					}
				}
				else if (shrinkTimer > 0)
				{
					shrinkTimer--;
				}
				else if ((double)((Component)__instance).transform.localScale.x < 1.5)
				{
					Transform transform2 = ((Component)__instance).transform;
					transform2.localScale += shrinkSpeed;
					Transform payloadPivot2 = __instance.payloadPivot;
					payloadPivot2.localScale += shrinkSpeed;
					__instance.maxDrivePower += 4f;
					__instance.maxSpeed += 2f / 3f;
					__instance.maxSpeedScale += 1f / 150f;
					__instance.drivePowerScale += 1f / 150f;
					((Component)OtherPatches.guy).transform.localScale = new Vector3(1.13f, 1.13f, 1.13f);
				}
			}
			if (PauseSystem.paused && debugTP && !__instance.guyActive)
			{
				debugTP = !debugTP;
				((Component)__instance).transform.SetPositionAndRotation(debugTPDest, MountainTownQt);
			}
			if (PauseSystem.paused && teleport && !__instance.guyActive)
			{
				if (OtherPatches.currentScene == 1)
				{
					((Component)__instance).transform.SetPositionAndRotation(MountainTownTP, MountainTownQt);
				}
				if (OtherPatches.currentScene == 5)
				{
					((Component)__instance).transform.SetPositionAndRotation(SnowyPeaksTP, SnowyPeaksQt);
				}
				else if (OtherPatches.currentScene == 4)
				{
					((Component)__instance).transform.SetPositionAndRotation(FishingTownTP, FishingTownQt);
				}
				teleport = false;
			}
			__instance.dirtColor = trailColor;
			__instance.smokeColor = trailColor;
		}

		[HarmonyPatch(typeof(sCarController), "GetMaterialIndex")]
		private static bool Prefix(sCarController __instance, ref int __result)
		{
			if (!PauseSystem.paused && !__instance.guyActive)
			{
				if (iceTrap)
				{
					iceTimer += 7000;
					iceTrap = false;
				}
				else if (iceTimer > 0)
				{
					__result = 3;
					iceTimer--;
					return false;
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(sCarController), "SetInput", new Type[] { typeof(Vector2) })]
		private static void Prefix(sCarController __instance, ref Vector2 __0)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (!PauseSystem.paused && !__instance.guyActive)
			{
				if (turnTrap)
				{
					turnTimer += 500;
					turnTrap = false;
					randomTurn = __0.x;
				}
				else if (turnTimer > 0)
				{
					__0 = new Vector2(randomTurn, __0.y);
					turnTimer--;
				}
				if (accelTrap)
				{
					accelTimer += 500;
					accelTrap = false;
				}
				else if (accelTimer > 0)
				{
					__0 = new Vector2(__0.x, 1f);
					accelTimer--;
				}
			}
		}

		[HarmonyPatch(typeof(sCharacterInteraction), "ExitObstructed")]
		private static void Prefix(sCharacterInteraction __instance, ref Vector3 __0)
		{
			if (shrinkTimer > 0)
			{
				__0.y += 0.5f;
			}
		}
	}
	[HarmonyPatch]
	public class DeathLinkPatches
	{
		private static readonly ArchipelagoClient archipelago = EasyDeliveryAP.ArchipelagoClient;

		private static bool dead;

		public static bool dying;

		[HarmonyPatch(typeof(DeathManager), "Update")]
		private static void Prefix(ref DeathManager __instance)
		{
			if (__instance.deathTime >= 50f)
			{
				__instance.deathTime = 20f;
			}
			if (!ArchipelagoClient.Authenticated)
			{
				return;
			}
			if (dead != __instance.dying)
			{
				dead = __instance.dying;
				if (__instance.dying && !dying)
				{
					archipelago.DeathLinkHandler.SendDeathLink();
				}
				dying = false;
			}
			if (dying && !dead && !__instance.dying)
			{
				sCharacterInteraction val = Object.FindObjectOfType<sCharacterInteraction>();
				val.hud.temperature = 0f;
			}
		}
	}
	[HarmonyPatch]
	public class ItemHandling
	{
		public static float pendingMoney = 0f;

		public static bool pendingItems;

		public static List<int> pendingItemIds = new List<int>();

		public static List<int> radio;

		public static bool pendingItem;

		public static bool pendingRemoval;

		public static int pendingItemId;

		public static bool pendingUpgrade;

		[HarmonyPatch(typeof(sHUD), "Update")]
		private static void Prefix(sHUD __instance)
		{
			if (pendingMoney != 0f)
			{
				ArchipelagoConsole.LogMessage($"Adding {pendingMoney}$");
				__instance.ReceivePayment(pendingMoney);
				pendingMoney = 0f;
			}
		}

		[HarmonyPatch(typeof(sItemManager), "Update")]
		private static void Postfix(sItemManager __instance)
		{
			if (pendingItems)
			{
				foreach (int pendingItemId in pendingItemIds)
				{
					ArchipelagoConsole.LogMessage($"Adding item id {pendingItemId} to inventory");
					__instance.AddToInventory(pendingItemId, 1);
				}
				pendingItemIds = new List<int>();
				pendingItems = false;
				EasyDeliveryAP.save.data.handledIndex = ArchipelagoClient.ServerData.Index;
			}
			radio = __instance.inventory;
			if (pendingItem)
			{
				ArchipelagoConsole.LogMessage($"Adding item id: {ItemHandling.pendingItemId}");
				__instance.AddToInventory(ItemHandling.pendingItemId, 1);
				pendingItem = false;
			}
			if (pendingRemoval)
			{
				ArchipelagoConsole.LogMessage($"Removing item id: {ItemHandling.pendingItemId}");
				__instance.inventory.Remove(ItemHandling.pendingItemId);
				pendingRemoval = false;
			}
		}

		[HarmonyPatch(typeof(TruckUpgrades), "LateUpdate")]
		private static void Prefix(TruckUpgrades __instance)
		{
			if (TestData.optionStartMap)
			{
				__instance.hasGPS = Items.GPS.Enabled;
			}
			if (APData.car_upgrades == "1")
			{
				__instance.hasGPS = Items.GPS.Enabled;
				if (APData.progressive_car_upgrades == "1")
				{
					__instance.hasTires = Items.ProgCarUpgrade.Received > 0;
					__instance.hasBumper = Items.ProgCarUpgrade.Received > 1;
					__instance.hasChains = Items.ProgCarUpgrade.Received > 2;
				}
				else
				{
					__instance.hasTires = Items.Tires.Received > 0;
					__instance.hasBumper = Items.Bumper.Received > 0;
					__instance.hasChains = Items.Chains.Received > 0;
				}
			}
			if (pendingUpgrade)
			{
				__instance.hasGPS = Items.GPS.Enabled;
				__instance.hasTires = Items.Tires.Enabled;
				__instance.hasBumper = Items.Bumper.Enabled;
				__instance.hasChains = Items.Chains.Enabled;
				pendingUpgrade = false;
			}
		}
	}
	[HarmonyPatch]
	public class LocationHandling
	{
		private static readonly ArchipelagoClient archipelago = EasyDeliveryAP.ArchipelagoClient;

		public static string jobStartTown;

		public static string jobStartCity;

		public static string jobStartShop;

		public static int jobDestinationIndex;

		public static string jobPayload;

		private static bool snowcat = false;

		[HarmonyPatch(typeof(jobBoard), "ConfirmJob")]
		private static void Postfix(jobBoard __instance)
		{
			ArchipelagoConsole.LogMessage($"Starting delivery from: {((Object)__instance.selectedJob.shop).name} in {((Object)__instance.selectedJob.from.town).name} - {__instance.cityName} (Dest index: {__instance.selectedJob.destinationIndex})");
			jobStartTown = ((Object)__instance.selectedJob.from.town).name;
			jobStartCity = __instance.selectedJob.startingCityName;
			jobStartShop = ((Object)__instance.selectedJob.shop).name;
			jobDestinationIndex = __instance.selectedJob.destinationIndex;
			if (!EasyDeliveryAP.debug)
			{
				return;
			}
			ArchipelagoConsole.LogMessage($"Destination node: {((Object)__instance.selectedJob.to).name} Bool: {__instance.selectedJob.to.destination}");
			foreach (sMapNode connection in __instance.selectedJob.to.connections)
			{
				ArchipelagoConsole.LogMessage($"Connections: {((Object)connection).name} Bool: {connection.destination}");
			}
		}

		[HarmonyPatch(typeof(jobBoard), "CompleteJob")]
		private static void Prefix(jobBoard __instance)
		{
			ArchipelagoConsole.LogMessage($"Completed delivering {((Object)__instance.selectedJob.payloadPrefab).name} to: {((Object)__instance.selectedJob.to.town).name} - {__instance.cityName} (Dest index: {jobDestinationIndex})");
			List<long> list = new List<long>();
			string key = jobStartTown + " to " + ((Object)__instance.selectedJob.to.town).name + " Delivery";
			string key2 = jobStartCity + " to " + __instance.selectedJob.destCityName + " Delivery";
			if (Locations.Deliveries.TryGetValue(key, out var value))
			{
				if (APData.perfect_deliveries == "0" || APData.perfect_deliveries == "1")
				{
					list.Add(value);
				}
				if ((APData.perfect_deliveries == "1" || APData.perfect_deliveries == "2") && __instance.recoveries <= 0)
				{
					list.Add(10000 + value);
				}
			}
			if (Locations.Deliveries.TryGetValue(key2, out var value2))
			{
				if (APData.perfect_deliveries == "0" || APData.perfect_deliveries == "1")
				{
					list.Add(value2);
				}
				if ((APData.perfect_deliveries == "1" || APData.perfect_deliveries == "2") && __instance.recoveries <= 0)
				{
					list.Add(10000 + value2);
				}
			}
			if (APData.payload_checks == "1" && Locations.PayloadDeliveries.TryGetValue(((Object)__instance.selectedJob.payloadPrefab).name, out var value3))
			{
				list.Add(value3);
			}
			archipelago.SendLocations(list.ToArray());
		}

		[HarmonyPatch(typeof(EndingManager), "SetEnding")]
		private static void Postfix(Ending __0, EndingManager __instance)
		{
			archipelago.SendCompletion();
		}

		[HarmonyPatch(typeof(GenericItemCheckout), "MakePayment")]
		private static void Prefix(float __0, GenericItemCheckout __instance)
		{
			if (EasyDeliveryAP.debug)
			{
				ArchipelagoConsole.LogMessage($"Buying {((Object)__instance.item).name} for {__0}$");
			}
			if (Locations.BlindBags.TryGetValue($"{OtherPatches.currentScene}{((Object)__instance.item).name}", out var value) && APData.blind_bags == "1")
			{
				archipelago.SendLocation(value);
			}
		}

		[HarmonyPatch(typeof(SnowcatManager), "EnableSnowcat")]
		private static void Prefix()
		{
			snowcat = true;
		}

		[HarmonyPatch(typeof(SnowcatManager), "EnableSnowcat")]
		private static void Postfix()
		{
			snowcat = false;
		}

		[HarmonyPatch(typeof(SnowcatManager), "ClosestIndex")]
		private static void Postfix(int __result)
		{
			ArchipelagoConsole.LogMessage($"SnowcatBobbleIndex: {__result}");
			if (snowcat)
			{
				archipelago.SendLocation(__result + 40);
			}
		}

		[HarmonyPatch(typeof(RoadSign), "Update")]
		private static void Postfix(RoadSign __instance)
		{
			//IL_000c: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)__instance.cam).transform.position - ((Component)__instance).transform.position;
			if (ArchipelagoClient.Authenticated && !(((Vector3)(ref val)).magnitude > 30f) && !(Vector3.Dot(((Component)__instance.cam).transform.forward, ((Vector3)(ref val)).normalized) > 0f))
			{
				Dictionary<string, PositionData> dictionary = new Dictionary<string, PositionData>();
				switch (OtherPatches.currentScene)
				{
				case 1:
					dictionary = Locations.MountainTownPositions;
					break;
				case 4:
					dictionary = Locations.FishingTownPositions;
					break;
				case 5:
					dictionary = Locations.SnowyPeaksPositions;
					break;
				}
				if (dictionary.TryGetValue(((object)((Component)__instance).gameObject.transform.position/*cast due to .constrained prefix*/).ToString(), out var value))
				{
					archipelago.SendLocations(new long[1] { value.LocationId });
				}
				else
				{
					ArchipelagoConsole.LogMessage($"Unregistered or knocked over sign: {((Component)__instance).gameObject.transform.position}");
				}
			}
		}
	}
	[HarmonyPatch]
	public class OtherPatches
	{
		private static readonly ArchipelagoClient archipelago = EasyDeliveryAP.ArchipelagoClient;

		public static int currentScene;

		public static GameObject upgradedBasedProgression;

		public static GameObject shopInteriors;

		public static GameObject nodes;

		public static sCarController car;

		public static sCharacterController guy;

		public static Transform[] radios;

		public static GameObject radio1;

		public static GameObject radio2;

		public static Dictionary<string, Transform> progression = new Dictionary<string, Transform>();

		public static Dictionary<string, Transform> storeInteriors = new Dictionary<string, Transform>();

		public static Dictionary<string, Transform> Nodes = new Dictionary<string, Transform>();

		public static Dictionary<string, sMapNode> MapNodes = new Dictionary<string, sMapNode>();

		[HarmonyPatch(typeof(EnergyDrink), "ButtonPressed")]
		private static void Prefix(ref EnergyDrink __instance, ref bool __state)
		{
			if (!Items.GPS.Enabled && !__instance.upgrades.hadGPS)
			{
				__instance.upgrades.hasGPS = true;
				__state = true;
			}
		}

		[HarmonyPatch(typeof(EnergyDrink), "ButtonPressed")]
		private static void Postfix(ref EnergyDrink __instance, ref bool __state)
		{
			if (__state)
			{
				__instance.upgrades.hasGPS = false;
				__state = false;
			}
		}

		[HarmonyPatch(typeof(SceneTransition), "LoadScene", new Type[] { typeof(int) })]
		private static bool Prefix(int __0)
		{
			currentScene = __0;
			if (__0 == 3)
			{
				ArchipelagoConsole.LogMessage("Starting new save");
				ItemHandling.pendingItemIds = new List<int>();
				foreach (ItemData value in Items.APIdToItem.Values)
				{
					switch (value.Id)
					{
					case 0:
					case 1:
					case 2:
					case 3:
					case 4:
					case 5:
					case 6:
					case 7:
					case 8:
					case 9:
					case 10:
					case 11:
					case 12:
					case 13:
					case 14:
					case 15:
					case 16:
					case 17:
					{
						for (int num = value.Received; num > 0; num--)
						{
							ItemHandling.pendingItemIds.Add(value.Id);
						}
						break;
					}
					}
				}
				return true;
			}
			return true;
		}

		[HarmonyPatch(typeof(SceneTransition), "fadeIn")]
		private static void Prefix(SceneTransition __instance)
		{
			if (currentScene == 4 || currentScene == 5)
			{
				shopInteriors = GameObject.Find("StoreInteriors");
				storeInteriors = new Dictionary<string, Transform>();
				Transform[] componentsInChildren = shopInteriors.GetComponentsInChildren<Transform>(true);
				foreach (Transform val in componentsInChildren)
				{
					storeInteriors.TryAdd(((Object)val).name, val);
				}
			}
			else if (currentScene == 1)
			{
				shopInteriors = GameObject.Find("Store Interiors");
				storeInteriors = new Dictionary<string, Transform>();
				Transform[] componentsInChildren2 = shopInteriors.GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren2)
				{
					storeInteriors.TryAdd(((Object)val2).name, val2);
				}
				radios = GameObject.Find("RadioStationManager").GetComponentsInChildren<Transform>(true);
				Transform[] array = radios;
				foreach (Transform val3 in array)
				{
					string name = ((Object)((Component)val3).gameObject).name;
					string text = name;
					if (!(text == "RadioStationOneActive"))
					{
						if (text == "RadioStationTwoActive")
						{
							radio2 = ((Component)val3).gameObject;
						}
					}
					else
					{
						radio1 = ((Component)val3).gameObject;
					}
				}
			}
			if (currentScene == 1 || currentScene == 4 || currentScene == 5)
			{
				nodes = GameObject.Find("NavigationNodes");
				Nodes = new Dictionary<string, Transform>();
				Transform[] componentsInChildren3 = nodes.GetComponentsInChildren<Transform>(true);
				foreach (Transform val4 in componentsInChildren3)
				{
					Nodes.TryAdd(((Object)val4).name, val4);
				}
				MapNodes = new Dictionary<string, sMapNode>();
				sMapNode[] componentsInChildren4 = nodes.GetComponentsInChildren<sMapNode>(true);
				foreach (sMapNode val5 in componentsInChildren4)
				{
					MapNodes.TryAdd(((Object)val5).name, val5);
				}
				guy = Object.FindObjectOfType<sCharacterController>();
			}
			else if (currentScene == 6)
			{
				guy = Object.FindObjectOfType<sCharacterController>();
			}
			RemoveGate();
			if (currentScene != 1 || !EasyDeliveryAP.debug)
			{
				return;
			}
			foreach (string key in MapNodes.Keys)
			{
				if (!Locations.MountainTownNode.TryGetValue(((Object)MapNodes[key]).name, out var value) || value.Town == "Upton")
				{
				}
				ArchipelagoConsole.LogMessage($"{key} - D: {MapNodes[key].destination} - E: {((Behaviour)MapNodes[key]).enabled}");
			}
		}

		public static void RemoveGate()
		{
			if (currentScene == 4 && (APData.radio_towers == "1" || APData.radio_towers == "3") && Items.RadioTower.Received >= 3)
			{
				GameObject obj = GameObject.Find("ResetContainer");
				if (obj != null)
				{
					obj.SetActive(false);
				}
				GameObject obj2 = GameObject.Find("ResetVolumes");
				if (obj2 != null)
				{
					obj2.SetActive(false);
				}
				GameObject obj3 = GameObject.Find("Destroy Gate Check");
				if (obj3 != null)
				{
					obj3.SetActive(false);
				}
				GameObject obj4 = GameObject.Find("GATE movable");
				if (obj4 != null)
				{
					obj4.SetActive(false);
				}
			}
		}

		[HarmonyPatch(typeof(sHUD), "Start")]
		private static void Postfix(sHUD __instance)
		{
			APGUI.hud = __instance;
		}

		[HarmonyPatch(typeof(InteractionPoint), "DoAction", new Type[] { })]
		[HarmonyPatch(typeof(InteractionPoint), "DoAction", new Type[] { typeof(int) })]
		private unsafe static bool Prefix(InteractionPoint __instance, ref string __state)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			__state = ((Object)__instance).name;
			Vector3 position = __instance.listener.transform.position;
			PositionData value;
			if (((Object)__instance).name == "throw away" || ((Object)__instance).name == "take")
			{
				Dictionary<string, PositionData> dictionary = new Dictionary<string, PositionData>();
				if (currentScene == 1)
				{
					dictionary = Locations.MountainTownPositions;
				}
				else if (currentScene == 4)
				{
					dictionary = Locations.FishingTownPositions;
				}
				else if (currentScene == 5)
				{
					dictionary = Locations.SnowyPeaksPositions;
				}
				if (dictionary.TryGetValue(((object)(*(Vector3*)(&position))/*cast due to .constrained prefix*/).ToString(), out value))
				{
					ArchipelagoConsole.LogMessage("VendingBin: " + value.Name, console: false);
					if (APData.lock_towns == "0")
					{
						goto IL_0116;
					}
					if (APData.lock_towns == "1")
					{
						ItemData itemData = Items.NameToItem[value.Town];
						if (itemData != null && itemData.Received > 0)
						{
							goto IL_0116;
						}
					}
				}
				else
				{
					ArchipelagoConsole.LogMessage($"VendingBin: {position}", console: false);
				}
			}
			goto IL_0150;
			IL_0116:
			archipelago.SendLocations(new long[1] { value.LocationId });
			goto IL_0150;
			IL_0150:
			if (currentScene == 6 && APData.require_handheld_radio == "1" && ((Object)__instance).name == "enter" && !ItemHandling.radio.Contains(17))
			{
				APGUI.Inform("Cannot enter without a Handheld Radio");
				return false;
			}
			if (((Object)__instance).name == "Snow Tires" && Items.Tires.Received == 0)
			{
				APGUI.Inform("Snow Tires can't\nbe bought yet");
				return false;
			}
			if (((Object)__instance).name == "Bumper Bar" && Items.Bumper.Received == 0)
			{
				APGUI.Inform("Bumper Bar can't\nbe bought yet");
				return false;
			}
			if (((Object)__instance).name == "Ice Chains" && Items.Chains.Received == 0)
			{
				APGUI.Inform("Ice Chains can't\nbe bought yet");
				return false;
			}
			if (((Object)__instance.listener).name == "Lighter" && Items.Lighter.Received == 0)
			{
				APGUI.Inform("Lighter can't\nbe bought yet");
				return false;
			}
			if (currentScene == 4 && ((Object)__instance.listener).name == "StationEntrance" && (APData.radio_towers == "1" || APData.radio_towers == "3") && Items.RadioTower.Received < 3)
			{
				APGUI.Inform("This door lacks radio signal");
				return false;
			}
			if ((((Object)__instance.listener).name == "FishingRod" && Items.FishingRod.Received == 0) || !(((Object)__instance.listener).name == "CookingPot") || Items.CookingPot.Received == 0)
			{
			}
			return true;
		}

		[HarmonyPatch(typeof(InteractionPoint), "DoAction", new Type[] { })]
		[HarmonyPatch(typeof(InteractionPoint), "DoAction", new Type[] { typeof(int) })]
		private static void Postfix(InteractionPoint __instance, string __state)
		{
			if (!(__state == "turn on"))
			{
				return;
			}
			if (currentScene == 1)
			{
				if (radio1.activeSelf)
				{
					archipelago.SendLocation(60L);
				}
				if (radio2.activeSelf)
				{
					archipelago.SendLocation(61L);
				}
			}
			else if (currentScene == 5)
			{
				archipelago.SendLocation(62L);
			}
			else if (currentScene == 4)
			{
				archipelago.SendLocation(63L);
			}
		}

		[HarmonyPatch(typeof(sSaveSystem), "OnApplicationQuit")]
		private static void Postfix()
		{
			archipelago.Disconnect();
		}

		[HarmonyPatch(typeof(sTeleporter), "Teleport")]
		private static void Prefix()
		{
			if (currentScene == 5)
			{
				try
				{
					((Component)storeInteriors["tableAndUpgrade"]).gameObject.SetActive(true);
				}
				catch
				{
				}
			}
		}

		[HarmonyPatch(typeof(jobBoard), "DrawJobList")]
		private static void Postfix(jobBoard __instance)
		{
			if (!ArchipelagoClient.Authenticated)
			{
				return;
			}
			ReadOnlyCollection<long> allMissingLocations = archipelago.session.Locations.AllMissingLocations;
			List<Job> jobs = __instance.jobs;
			for (int num = jobs.Count - 1; num >= 0; num--)
			{
				Job val = jobs[num];
				int num2 = 0;
				bool flag = false;
				int value5;
				if (val.isIntercity)
				{
					string text;
					if (((Object)val.to).name == "Mountain Town")
					{
						Locations.MountainTownIndex.TryGetValue(val.destinationIndex, out var value);
						text = value.Town;
					}
					else if (((Object)val.to).name == "Snowy Peaks")
					{
						Locations.SnowyPeaksIndex.TryGetValue(val.destinationIndex, out var value2);
						text = value2.Town;
					}
					else if (((Object)val.to).name == "Fishing Town")
					{
						Locations.FishingTownIndex.TryGetValue(val.destinationIndex, out var value3);
						text = value3.Town;
					}
					else
					{
						text = "";
					}
					((ScreenProgram)__instance).R.put(text, 25f, 24f + (6f + (float)(num * 4)) * 8f);
					if (Locations.Deliveries.TryGetValue(((Object)val.from.town).name + " to " + text + " Delivery", out var value4))
					{
						if (allMissingLocations.Contains(value4) && (APData.perfect_deliveries == "0" || APData.perfect_deliveries == "1"))
						{
							num2++;
							flag = APData.IsHinted(value4, flag);
						}
						if (allMissingLocations.Contains(value4 + 10000) && (APData.perfect_deliveries == "1" || APData.perfect_deliveries == "2"))
						{
							num2++;
							flag = APData.IsHinted(value4 + 10000, flag);
						}
					}
				}
				else if (Locations.Deliveries.TryGetValue(((Object)val.from.town).name + " to " + ((Object)val.to.town).name + " Delivery", out value5))
				{
					if (allMissingLocations.Contains(value5) && (APData.perfect_deliveries == "0" || APData.perfect_deliveries == "1"))
					{
						num2++;
						flag = APData.IsHinted(value5, flag);
					}
					if (allMissingLocations.Contains(value5 + 10000) && (APData.perfect_deliveries == "1" || APData.perfect_deliveries == "2"))
					{
						num2++;
						flag = APData.IsHinted(value5 + 10000, flag);
					}
				}
				if (Locations.Deliveries.TryGetValue(val.startingCityName + " to " + val.destCityName + " Delivery", out var value6))
				{
					if (allMissingLocations.Contains(value6) && (APData.perfect_deliveries == "0" || APData.perfect_deliveries == "1"))
					{
						num2++;
						flag = APData.IsHinted(value6, flag);
					}
					if (allMissingLocations.Contains(value6 + 10000) && (APData.perfect_deliveries == "1" || APData.perfect_deliveries == "2"))
					{
						num2++;
						flag = APData.IsHinted(value6 + 10000, flag);
					}
				}
				if (Locations.PayloadDeliveries.TryGetValue(((Object)val.payloadPrefab).name, out var value7) && allMissingLocations.Contains(value7) && APData.payload_checks == "1")
				{
					num2++;
					flag = APData.IsHinted(value7, flag);
				}
				if (num2 != 0)
				{
					if (flag)
					{
						((ScreenProgram)__instance).R.fput("!", 120f, 24f + (6f + (float)(num * 4)) * 8f, 0f, 13f, 0f, -1);
					}
					((ScreenProgram)__instance).R.fput(num2.ToString(), 128f, 24f + (6f + (float)(num * 4)) * 8f, 0f, 13f, 0f, -1);
				}
			}
		}
	}
	[HarmonyPatch]
	public class ScenePatches
	{
		public static string currentScene;

		public static string lastScene;

		[HarmonyPatch(typeof(MenuScreenTransition), "Update")]
		private static void Postfix(MenuScreenTransition __instance)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Scene scene = __instance.screen.scene;
			currentScene = ((Scene)(ref scene)).name;
			if (currentScene != lastScene)
			{
				ManualLogSource bepinLogger = EasyDeliveryAP.BepinLogger;
				scene = __instance.screen.scene;
				bepinLogger.LogMessage((object)("Menu Screen: " + ((Scene)(ref scene)).name));
				if (currentScene == "TitleScreen")
				{
					EasyDeliveryAP.save.data.handledIndex = 0;
				}
				if (lastScene == "TitleScreen")
				{
					APData.SaveConnectionOrConnect();
				}
			}
			lastScene = currentScene;
		}
	}
	public class Testing
	{
		private static readonly ArchipelagoClient archipelago = EasyDeliveryAP.ArchipelagoClient;

		private static List<string> signs = new List<string>();

		public static GameObject tiresUpgrade;

		public static GameObject bumperUpgrade;

		public static GameObject chainsUpgrade;

		[HarmonyPatch(typeof(sGoals), "CompleteGoal")]
		private static void Prefix(Goal __0, sGoals __instance)
		{
			ArchipelagoConsole.LogMessage("Goal completed: " + __0.name);
		}

		[HarmonyPatch(typeof(GenericItemCheckout), "MakePayment")]
		private static void Prefix(float __0, GenericItemCheckout __instance)
		{
			ArchipelagoConsole.LogMessage($"Buying {((Object)__instance.item).name} for {__0}$");
		}

		[HarmonyPatch(typeof(DeliveryResults), "DoSequence")]
		private static void Prefix(DeliveryResults __instance)
		{
			ArchipelagoConsole.LogMessage($"Paying: {__instance.paying}");
		}

		[HarmonyPatch(typeof(jobBoard), "GenerateJobBetter")]
		private static void Prefix(int __0, ref jobBoard __instance)
		{
			ArchipelagoConsole.LogMessage("Towns:");
			Transform[] towns = __instance.navigation.towns;
			foreach (Transform val in towns)
			{
				ArchipelagoConsole.LogMessage("  " + ((Object)val).name);
			}
			foreach (ShopInfo shopNode in __instance.navigation.shopNodes)
			{
				ArchipelagoConsole.LogMessage("Shop: " + ((Object)shopNode).name + " Node: " + ((Object)shopNode.node).name);
			}
			foreach (sMapNode allDestinationNode in __instance.navigation.allDestinationNodes)
			{
			}
			TunnelNode[] tunnelNodes = __instance.tunnelNodes;
			foreach (TunnelNode val2 in tunnelNodes)
			{
			}
			for (int num = __instance.jobs.Count - 1; num >= 0; num--)
			{
				ArchipelagoConsole.LogMessage(((Object)__instance.jobs[num].to).name ?? "");
			}
		}

		[HarmonyPatch(typeof(jobBoard), "GenerateJobBetter")]
		private static void Postfix(ref Job __result)
		{
		}

		[HarmonyPatch(typeof(sHUD), "ReceivePayment")]
		private static void Prefix(ref float __0)
		{
			ArchipelagoConsole.LogMessage($"Money Recieved: {__0}");
		}

		[HarmonyPatch(typeof(UpgradeCheckout), "Update")]
		private static void Postfix(UpgradeCheckout __instance)
		{
			if (!((Object)(object)__instance.inventory.heldItem != (Object)null))
			{
			}
		}

		[HarmonyPatch(typeof(ConditionalToggle), "Toggle")]
		private static void Postfix(ConditionalToggle __instance)
		{
			ArchipelagoConsole.LogMessage("Toggle: " + ((Object)__instance).name);
		}

		[HarmonyPatch(typeof(CreditsHUD), "FrameUpdate")]
		private static void Prefix(CreditsHUD __instance)
		{
			ArchipelagoConsole.LogMessage("Credits: " + ((Object)__instance).name);
		}

		[HarmonyPatch(typeof(EndingManager), "SetEnding")]
		private static void Postfix(Ending __0, EndingManager __instance)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ArchipelagoConsole.LogMessage($"Ending: {__instance.currentEnding}");
		}

		[HarmonyPatch(typeof(FishingHole), "Catch")]
		private static void Prefix(FishingHole __instance)
		{
			if (__instance.hooked)
			{
				ArchipelagoConsole.LogMessage("Fish Caught");
			}
		}

		[HarmonyPatch(typeof(GachaPurchase), "MakePayment")]
		private static void Postfix(GachaPurchase __instance)
		{
			ArchipelagoConsole.LogMessage($"Gacha: {__instance.newItem}");
		}

		[HarmonyPatch(typeof(GarbageCan), "ThrowOut")]
		private static void Prefix(int __0, GarbageCan __instance)
		{
		}

		[HarmonyPatch(typeof(GiveGoal), "Start")]
		private static void Prefix(GiveGoal __instance)
		{
			ArchipelagoConsole.LogMessage("GiveGoal");
			ArchipelagoConsole.LogMessage($"Goal: {__instance.goalIndex}");
		}

		[HarmonyPatch(typeof(GiveProgram), "Start")]
		private static void Prefix(GiveProgram __instance)
		{
			ArchipelagoConsole.LogMessage("GiveProgram");
			ArchipelagoConsole.LogMessage("Program: " + __instance.programName);
		}

		[HarmonyPatch(typeof(HandheldRadio), "ButtonPressed")]
		private static void Prefix(HandheldRadio __instance)
		{
			ArchipelagoConsole.LogMessage("Hello");
		}

		[HarmonyPatch(typeof(BigDoor), "Start")]
		private static void Prefix(BigDoor __instance)
		{
			ArchipelagoConsole.LogMessage($"Door: {__instance.doorOpenDuration}");
		}

		[HarmonyPatch(typeof(sTeleporter), "Update")]
		private static void Prefix(sTeleporter __instance)
		{
			if (__instance.teleporting)
			{
				ArchipelagoConsole.LogMessage($"Teleporter: {((Object)__instance).name}\nLighter: {Items.Lighter.Received}");
			}
			switch (OtherPatches.currentScene)
			{
			case 5:
				if (((Object)__instance).name == "StoreShop AutoShop" && Items.Tires.Enabled)
				{
					Items.Tires.Toggle = true;
					Items.Tires.Enabled = false;
				}
				else if (((Object)__instance).name == "ShopExit" && Items.Tires.Toggle)
				{
					Items.Tires.Toggle = false;
					Items.Tires.Enabled = true;
				}
				break;
			case 4:
				if (((Object)__instance).name == "StoreShop AutoShop" && Items.Bumper.Enabled)
				{
					Items.Bumper.Toggle = true;
					Items.Bumper.Enabled = false;
				}
				else if (((Object)__instance).name == "ShopExit" && Items.Bumper.Toggle)
				{
					Items.Bumper.Toggle = false;
					Items.Bumper.Enabled = true;
				}
				if (((Object)__instance).name == "StoreShop AutoShop" && Items.Chains.Enabled)
				{
					Items.Chains.Toggle = true;
					Items.Chains.Enabled = false;
				}
				else if (((Object)__instance).name == "ShopExit" && Items.Chains.Toggle)
				{
					Items.Chains.Toggle = false;
					Items.Chains.Enabled = true;
				}
				break;
			case 8:
				break;
			case 6:
			case 7:
				break;
			}
		}

		[HarmonyPatch(typeof(sSceneConnection), "Update")]
		private static bool Prefix(sSceneConnection __instance)
		{
			if (__instance.connecting)
			{
				ArchipelagoConsole.LogMessage($"Scene connect: {((Object)__instance).name} {__instance.nextScene}");
			}
			if (__instance.nextScene != 3 || __instance.nextScene != 1)
			{
				return true;
			}
			return true;
		}

		[HarmonyPatch(typeof(RoadSign), "Update")]
		private static void Postfix(RoadSign __instance)
		{
			//IL_000c: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)__instance.cam).transform.position - ((Component)__instance).transform.position;
			if (((Vector3)(ref val)).magnitude > 30f || Vector3.Dot(((Component)__instance.cam).transform.forward, ((Vector3)(ref val)).normalized) > 0f)
			{
				return;
			}
			string item = $"{((Component)__instance).gameObject.transform.position} Enter: {__instance.enterLabel} Exit: {__instance.exitLabel}";
			if (signs.Contains(item))
			{
				return;
			}
			signs.Add(item);
			ArchipelagoConsole.LogMessage($"Road sign: {((Object)__instance).name}\n{((Object)((Component)__instance).transform).name}\n {__instance.enterLabel}\n{__instance.exitLabel}\n{((Component)__instance).gameObject.transform.position}");
			foreach (string sign in signs)
			{
				ArchipelagoConsole.LogMessage("{\"" + sign + "\", }, \\\\ " + __instance.enterLabel);
			}
		}

		[HarmonyPatch(typeof(Crashable), "Start")]
		private static void Prefix(Crashable __instance)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			ArchipelagoConsole.LogMessage($"Crashable: {((Object)__instance).name}, {((Component)__instance).transform.position}");
		}

		[HarmonyPatch(typeof(InteractiveToggle), "ToggleOn")]
		private static void Prefix(InteractiveToggle __instance)
		{
			ArchipelagoConsole.LogMessage("Interactive toggle: " + ((Object)__instance).name);
		}

		[HarmonyPatch(typeof(PurchasableItem), "OnEnable")]
		private static void Prefix(PurchasableItem __instance)
		{
			ArchipelagoConsole.LogMessage("PurchasableItem: " + ((Object)__instance.pickup.listener).name);
		}

		[HarmonyPatch(typeof(PurchaseItem), "Start")]
		private static void Prefix(PurchaseItem __instance)
		{
			ArchipelagoConsole.LogMessage("Purchase Item: " + ((Object)__instance).name);
		}

		[HarmonyPatch(typeof(PurchaseUpgrade), "Start")]
		private static void Postfix(PurchaseUpgrade __instance)
		{
			ArchipelagoConsole.LogMessage("Purchase Upgrade: " + ((Object)__instance.pickup.interactPointsObject).name);
			switch (((Object)__instance.upgradeToggle).name)
			{
			case "TiresUpgrade":
				tiresUpgrade = __instance.pickup.interactPointsObject;
				break;
			case "BumperUpgrade":
				bumperUpgrade = __instance.pickup.interactPointsObject;
				break;
			case "IceChains":
				chainsUpgrade = __instance.pickup.interactPointsObject;
				break;
			}
		}

		[HarmonyPatch(typeof(InventoryWatcher), "Start")]
		private static void Prefix(InventoryWatcher __instance)
		{
			ArchipelagoConsole.LogMessage($"InventoryWatcher: {__instance.pairs[0].hasItem}");
			foreach (itemObjectPair pair in __instance.pairs)
			{
				ArchipelagoConsole.LogMessage(((Object)pair.hasItem).name ?? "");
			}
		}

		[HarmonyPatch(typeof(SnowTires), "Start")]
		private static void Postfix(SnowTires __instance)
		{
			ArchipelagoConsole.LogMessage($"Snow Tires: {__instance}");
		}

		[HarmonyPatch(typeof(TunnelNode), "Start")]
		private static void Postfix(TunnelNode __instance)
		{
			ArchipelagoConsole.LogMessage("TunnelNode: " + ((Object)__instance).name);
		}

		[HarmonyPatch(typeof(ToggleMapNode), "SetState")]
		private static void Prefix(ToggleMapNode __instance)
		{
			ArchipelagoConsole.LogMessage("ToggleMapNode: " + ((Object)__instance.nodeToToggle).name);
		}
	}
	[HarmonyPatch]
	public class TunnelPatches
	{
		[HarmonyPatch(typeof(sSceneConnection), "Update")]
		private static bool Prefix(sSceneConnection __instance)
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			string blocked_tunnels = APData.blocked_tunnels;
			if (blocked_tunnels == "0" || __instance.justConnected || __instance.nextScene == 1 || Utility.IsNullOrWhiteSpace(blocked_tunnels))
			{
				return true;
			}
			if (__instance.nextScene == 5 && ((Items.TunnelSP.Received > 0 && blocked_tunnels == "1") || blocked_tunnels != "1"))
			{
				return true;
			}
			if (__instance.nextScene == 4 && ((Items.TunnelFT.Received > 0 && blocked_tunnels == "1") || blocked_tunnels != "1"))
			{
				return true;
			}
			if (__instance.nextScene == 6 && Items.TunnelFactory.Received > 0)
			{
				return true;
			}
			if (Vector3.Distance(((Component)__instance).gameObject.transform.position, ((Component)__instance.car).transform.position) < 25f)
			{
				APGUI.Warning("tunnel under construction");
			}
			return false;
		}
	}
	[BepInPlugin("com.aeromaze.easyDeliveryAP", "EasyDeliveryAP", "0.3.0")]
	public class EasyDeliveryAP : BaseUnityPlugin
	{
		public const string PluginGUID = "com.aeromaze.easyDeliveryAP";

		public const string PluginName = "EasyDeliveryAP";

		public const string PluginVersion = "0.3.0";

		public const string ModDisplayInfo = "EasyDeliveryAP v0.3.0";

		private const string APDisplayInfo = "Archipelago v0.6.7";

		public static ManualLogSource BepinLogger;

		public static ArchipelagoClient ArchipelagoClient;

		public static bool deathLink = false;

		internal static ModdedSaveSystem<APSaveFile> save = new ModdedSaveSystem<APSaveFile>("Archipelago");

		public static ConfigEntry<bool> configConsole;

		public static ConfigEntry<bool> configDeathLink;

		public static ConfigEntry<bool> configAutoConnect;

		public static ConfigEntry<bool> configDebug;

		public static File TrackerFile;

		public static Vector2 trackerPosition;

		public static bool debug = false;

		private string itemId = "";

		private string obj = "";

		private bool upton = true;

		private string debugNode = "";

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			BepinLogger = ((BaseUnityPlugin)this).Logger;
			ArchipelagoClient = new ArchipelagoClient();
			ArchipelagoConsole.Awake();
			new Harmony("com.aeromaze.easyDeliveryAP").PatchAll();
			configDeathLink = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DeathLink", false, "Turn on DeathLink");
			configConsole = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowConsole", false, "Show the ingame console");
			configAutoConnect = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoConnect", true, "Automatically connect to the previous connection when opening a save");
			if (debug)
			{
				configDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebug", true, "Enable debug buttons");
			}
			EasyAPI.AddConfig("Archipelago", ((BaseUnityPlugin)this).Config);
			TrackerFile = EasyAPI.InstantiateFile();
			TrackerFile.name = "Tracker";
			TrackerFile.type = (FileType)0;
			TrackerFile.icon = 3;
			TrackerFile.iconHover = 4;
			TrackerFile.data = "listener_" + TrackerFile.name;
			trackerPosition.x = 0.35f;
			trackerPosition.y = 3.15f;
			TrackerFile.position = trackerPosition;
			EasyAPI.AddListener<TrackerApp>(TrackerFile.name);
			EasyAPI.AddFile((DesktopLocation)0, TrackerFile);
			((BaseUnityPlugin)this).Logger.LogMessage((object)"EasyDeliveryAP v0.3.0 loaded!");
			Items.GPS.Enabled = true;
		}

		private void Update()
		{
			if (DeathLinkHandler.deathLinkEnabled != configDeathLink.Value && ArchipelagoClient.Authenticated)
			{
				ArchipelagoClient.DeathLinkHandler?.ToggleDeathLink();
			}
			if (!ArchipelagoClient.Authenticated)
			{
				APGUI.Warning("Not Connected");
			}
			debug = configDebug?.Value ?? debug;
		}

		private void OnGUI()
		{
			//IL_0015: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: 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_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (mi

BepInEx/plugins/EasyDeliveryAP/Archipelago.MultiClient.Net.dll

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

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

	bool Contains(T item);

	void UnionWith(T[] otherSet);

	T[] ToArray();

	ReadOnlyCollection<T> AsToReadOnlyCollection();

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

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

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

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

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

		IReceivedItemsHelper Items { get; }

		ILocationCheckHelper Locations { get; }

		IPlayerHelper Players { get; }

		IDataStorageHelper DataStorage { get; }

		IConnectionInfoProvider ConnectionInfo { get; }

		IRoomStateHelper RoomState { get; }

		IMessageLogHelper MessageLog { get; }

		IHintsHelper Hints { get; }

		Task<RoomInfoPacket> ConnectAsync();

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

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

		private ConnectionInfoHelper connectionInfo;

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

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

		public IArchipelagoSocketHelper Socket { get; }

		public IReceivedItemsHelper Items { get; }

		public ILocationCheckHelper Locations { get; }

		public IPlayerHelper Players { get; }

		public IDataStorageHelper DataStorage { get; }

		public IConnectionInfoProvider ConnectionInfo => connectionInfo;

		public IRoomStateHelper RoomState { get; }

		public IMessageLogHelper MessageLog { get; }

		public IHintsHelper Hints { get; }

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

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

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

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

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

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

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

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

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

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

		void SetClientState(ArchipelagoClientState state);

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

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

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

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

		public int Team { get; }

		public int Slot { get; }

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

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

		public ConnectionRefusedError[] ErrorCodes { get; }

		public string[] Errors { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public byte R { get; set; }

		public byte G { get; set; }

		public byte B { get; set; }

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

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

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

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

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

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

	}
	public class DataStorageElement
	{
		internal DataStorageElementContext Context;

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

		internal DataStorageHelper.DataStorageUpdatedHandler Callbacks;

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

		private JToken cachedValue;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

		public long ItemId { get; }

		public long LocationId { get; }

		public PlayerInfo Player { get; }

		public ItemFlags Flags { get; }

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

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

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

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

		public string ItemGame { get; }

		public string LocationGame { get; }

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

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

		public bool IsReceiverRelatedToActivePlayer { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public NetworkVersion()
		{
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private Callback()
		{
		}

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

		internal JToken Value { get; set; }

		private AdditionalArgument()
		{
		}

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

		public long LocationId { get; set; }

		public int PlayerSlot { get; set; }

		public ItemFlags Flags { get; set; }

		public string ItemGame { get; set; }

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

		public PlayerInfo Player { get; set; }

		public string ItemName { get; set; }

		public string LocationName { get; set; }

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

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

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

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

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

		public ILocationCheckHelper Locations { get; set; }

		public IPlayerHelper PlayerHelper { get; set; }

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

		public long ItemId { get; }

		public int Player { get; }

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

		public int Player { get; }

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

		public MessagePartType Type { get; internal set; }

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

		public PaletteColor? PaletteColor { get; protected set; }

		public bool IsBackgroundColor { get; internal set; }

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

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

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

		public int SlotId { get; }

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

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

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

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

		public PlayerInfo Receiver { get; }

		public PlayerInfo Sender { get; }

		public bool IsReceiverTheActivePlayer => Receiver == ActivePlayer;

		public bool IsSenderTheActivePlayer => Sender == ActivePlayer;

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

		public ItemInfo Item { get; }

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

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

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

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

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

		public PlayerInfo Player { get; }

		public bool IsActivePlayer => Player == ActivePlayer;

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

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

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

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

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

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

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

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

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

		internal T Socket;

		private readonly int bufferSize;

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

		public event ArchipelagoSocketHelperDelagates.PacketReceivedHandler PacketReceived;

		public event ArchipelagoSocketHelperDelagates.PacketsSentHandler PacketsSent;

		public event ArchipelagoSocketHelperDelagates.ErrorReceivedHandler ErrorReceived;

		public event ArchipelagoSocketHelperDelagates.SocketClosedHandler SocketClosed;

		public event ArchipelagoSocketHelperDelagates.SocketOpenedHandler SocketOpened;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		int Team { get; }

		int Slot { get; }

		string[] Tags { get; }

		ItemsHandlingFlags ItemsHandlingFlags { get; }

		string Uuid { get; }

		void UpdateConnectionOptions(string[] tags);

		void UpdateConnectionOptions(ItemsHandlingFlags itemsHandlingFlags);

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

		public string Game { get; private set; }

		public int Team { get; private set; }

		public int Slot { get; private set; }

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

		public ItemsHandlingFlags ItemsHandlingFlags { get; internal set; }

		public string Uuid { get; private set; }

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

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

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

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

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

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

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

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

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

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

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

		private readonly IArchipelagoSocketHelper socket;

		private readonly IConnectionInfoProvider connectionInfoProvider;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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